Back to APIs list

Telegram API examples & templates

Use these vals as a playground to view and fork Telegram API examples and templates on Val Town. Run any example below or find templates that can be used as a pre-built solution.

Send yourself a Telegram message

Inspired by console.email, this val lets you send yourself a Telegram message via the valtown_bot from any of your vals

Create val@me.telegram("hi to me on telegram!")

Installation

1. Start a conversation with valtown_bot

Click here: https://t.me/valtown_bot

2. Copy your Secret

3. Save in your secrets under telegramSecret

4. Fork this val & run it

Save your own private version of a telegram function to your account by forking this val: https://www.val.town/v/pomdtr.telegram

5. Send a test message!

Create valawait @me.telegram("hi to me on telegram!")

PS: the bot code is available here

Readme
1
2
3
4
5
6
7
8
9
10
import process from "node:process";
import { runVal } from "https://esm.town/v/std/runVal";
export async function telegram(message: string) {
return runVal(
"pomdtr.sendToTelegram",
process.env.telegramSecret,
message,
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import { tgEchoCommand } from "https://esm.town/v/smalldogenergy/tgEchoCommand";
import { tgWeatherCommand } from "https://esm.town/v/smalldogenergy/tgWeatherCommand";
import { tgUpdates } from "https://esm.town/v/smalldogenergy/tgUpdates";
import process from "node:process";
export async function tgWebhook(req, res) {
const botSecretToken = req.get("X-Telegram-Bot-Api-Secret-Token");
if (botSecretToken !== process.env.tgBotSecretToken) {
res.status(401).json({ ok: false, description: "Unauthorized" });
return;
}
const payload: TgUpdatePayload = req.body;
if (payload.message) {
tgUpdates.push(payload);
const args = {
chatId: payload.message.chat.id,
text: payload.message.text,
languageCode: payload.message.from.language_code,
};
if (args.text.startsWith("/weather")) {
tgWeatherCommand(args);
} else {
tgEchoCommand(args);
}
}
res.status(200).json({ ok: true });
}
interface TgUpdatePayload {
update_id: number;
message?: TgMessage;
}
interface TgMessage {
from: { language_code: "string" };
chat: { id: number };
text: string;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { fetch } from "https://esm.town/v/std/fetch";
import process from "node:process";
import { secretToTelegramChat } from "https://esm.town/v/pomdtr/secretToTelegramChat";
export async function sendToTelegram(secret: string, message: string) {
const chatID = secretToTelegramChat[secret];
const resp = await fetch(
`https://api.telegram.org/bot${process.env.telegramToken}/sendMessage?chat_id=${chatID}&text=${message}`,
{
method: "POST",
},
);
if (resp.status != 200) {
throw new Error(`An error occured: ${resp.statusText}`);
}
}
1
2
3
4
5
6
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export const telegramGetMe = async (botToken: string) =>
fetchJSON(
`https://api.telegram.org/bot${botToken}/getMe`,
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage";
import process from "node:process";
export const telegramWebhookEchoMessage = async (
req: express.Request,
res: express.Response,
) => {
// Verify this webhook came from our bot
if (
req.get("x-telegram-bot-api-secret-token") !==
process.env.telegramWebhookSecret
) {
return res.status(401);
}
// Echo back the user's message
const text: string = req.body.message.text;
const chatId: number = req.body.message.chat.id;
telegramSendMessage(
process.env.telegramBotToken,
{ chat_id: chatId, text },
);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
export const telegramBot = async (req: express.Request, res: express.Response) => {
// if (
// req.get("x-telegram-bot-api-secret-token") !==
// @me.secrets.telegram_webhook_token
// ) {
// return res.status(401);
// }
// const chatId: number = req.body.message.chat.id;
// if (chatId.toString() !== @me.secrets.telegram_chat_id) {
// return res.status(401);
// }
// const text: string = await @me.gptChat(req.body.message.text);
// @vtdocs.telegramSendMessage(
// @me.secrets.telegram_api_token,
// { chat_id: chatId, text },
// );
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export const telegramSendMessage = async (botToken: string, options: {
chat_id: string | number;
text: string;
message_thread_id?: number;
parse_mode?: string;
entities?: any[];
disable_web_page_preview?: boolean;
disable_notification?: boolean;
protect_content?: boolean;
reply_to_message_id?: number;
allow_sending_without_reply?: boolean;
reply_markup?: any[];
}) =>
fetchJSON(
`https://api.telegram.org/bot${botToken}/sendMessage`,
{
method: "POST",
body: JSON.stringify({ ...options }),
},
);

The beating heart of the @ValTownBot on Telegram: https://www.val.town/v/stevekrouse.telegram

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import { fetch } from "https://esm.town/v/std/fetch";
import { isValidURL } from "https://esm.town/v/stevekrouse/isValidURL";
import { email } from "https://esm.town/v/std/email?v=9";
import { set } from "https://esm.town/v/std/set?v=11";
import { nanoid } from "https://esm.town/v/stevekrouse/nanoid";
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage?v=5";
import { telegramValTownBotSecrets } from "https://esm.town/v/stevekrouse/telegramValTownBotSecrets";
import process from "node:process";
export const telegramValTownBotWebhook = async (
req: express.Request,
res: express.Response,
) => {
// Verify this webhook came from our bot
if (
req.get("x-telegram-bot-api-secret-token") !==
process.env.telegramWebhookSecret
) {
return res.status(401);
}
res.status(200).end(); // TODO sometimes we do want telegram to try again, so make this more nuanced
const text: string = req.body.message.text;
const chatId: number = req.body.message.chat.id;
let chat = telegramValTownBotSecrets.find((c) =>
c.chatId === chatId
);
// Helper function to message back the user that triggered this webhook
let messageBack = (message) =>
telegramSendMessage(process.env.telegramBot, {
chat_id: chatId,
text: message,
});
// Save a new user
if (!chat) {
let secret = await nanoid();
telegramValTownBotSecrets.push({
chatId,
secret,
});
await set(
"telegramValTownBotSecrets",
telegramValTownBotSecrets,
);
await email({
text: JSON.stringify(req.body, null, 2),
subject: "New Telegram Bot User!",
});
return messageBack(
`Your secret is ${secret} - Instructions: https://www.val.town/v/stevekrouse.telegram`,
);
}
// Save a webhook
if (chat.settingWebhook) {
chat.settingWebhook = false;
let url = text.trim();
if (!isValidURL(url)) {
return messageBack("Not a valid webhook URL:\n\n" + url);
}
chat.webhook = url;
try {
await fetch(url, { method: "POST", body: JSON.stringify(req.body) });
return messageBack(
"Webhook setup!\n\nWe forwarded your last message to your webhook as a test",
);
}
catch (e) {
return messageBack(
"Webhook setup!\n\nWe forwarded your last message to your webhook as a test, but it errored.",
);
}
}
// Enter webhook-saving mode
if (text === "/webhook") {
chat.settingWebhook = true;
return messageBack(
"What's the URL of the webhook you'd like your messages to go to?",
);
}
if (text === "/roll") {
chat.secret = await nanoid();
return messageBack(
`Your new secret is ${chat.secret} - Instructions: https://www.val.town/v/stevekrouse.telegram`,
);
}
if (text === "/help") {
return messageBack(
"@ValTownBot lets your send and receive Telegram messages from Val Town\n\n/roll - Roll your secret\n/webhook - Register a webhook\n\nLearn more: https://www.val.town/v/stevekrouse.telegram",
);
}
// Send your message to your webhook if you have one set
if (chat.webhook) {
return fetch(chat.webhook, {
method: "POST",
body: JSON.stringify(req.body),
});
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { fetch } from "https://esm.town/v/std/fetch";
export async function sendTelegramMessage(params: {
token: string,
chatId: string,
text: string,
}) {
console.log(params);
const { token, chatId, text } = params;
return fetch(
`https://api.telegram.org/bot${token}/sendMessage?chat_id=${chatId}&text=${encodeURIComponent(
text
)}`
);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import process from "node:process";
import { telegramSetWebhook } from "https://esm.town/v/vtdocs/telegramSetWebhook?v=2";
export const setWebhookExample = telegramSetWebhook(
process.env.telegramBotToken,
{
// Replace this with _your_ express endpoint
url: "https://dpetrouk-telegramWebhookEchoMessage.express.val.run",
// Optionally, filter what kind of updates you want to receive here
allowed_updates: ["message"],
secret_token: process.env.telegramWebhookSecret,
},
);
// Forked from @vtdocs.setWebhookExample

Telegram DALLE Bot

A personal telegram bot you can message to create images with OpenAI's DALLE

DALLE: A Macintosh II sitting on a desk, painted by Picasso in his blue period.

Set up yours

  1. fork this val

  2. speak to telegram’s https://t.me/botfather to create a bot and obtain a bot token

  3. set the bot token as a val town secret called telegramDalleBotToken

  4. add a random string as a val town secret called telegramDalleBotWebhookSecret

  5. set up your webhook with telegram like this:

Create val// paste and run this in your workspace on here @vtdocs.telegramSetWebhook(@me.secrets.telegramDalleBotToken, { url: /* your fork's express endpoint (click the three dots on a val) */, allowed_updates: ["message"], secret_token: @me.secrets.telegramDalleBotWebhookSecret, });
  1. message your bot some prompts!

(if you get stuck, you can refer to the telegram echo bot guide from docs.val.town)

Readme
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import { telegramSendPhoto } from "https://esm.town/v/vtdocs/telegramSendPhoto?v=1";
import { textToImageDalle } from "https://esm.town/v/hootz/textToImageDalle";
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage?v=5";
import process from "node:process";
export const telegramDalleBot = async (
req: express.Request,
res: express.Response,
) => {
if (
req.get("x-telegram-bot-api-secret-token") !==
process.env.telegramDalleBotWebhookSecret
) {
return res.status(401);
}
const text: string = req.body.message.text;
const chatId: number = req.body.message.chat.id;
// when you start a chat, this event happens
if (text === "/start") {
telegramSendMessage(
process.env.telegramDalleBotToken,
{ chat_id: chatId, text: "send prompt, get an image!" },
);
return;
}
// otherwise, generate an image!
try {
const imageURL =
(await textToImageDalle(
process.env.openai,
text,
1,
"1024x1024",
))
.data[0].url;
telegramSendPhoto(
process.env.telegramDalleBotToken,
// caption is limited to 1024 characters
{ chat_id: chatId, photo: imageURL, caption: text.slice(0, 1024) },
);
}
catch (e) {
// report any errors via telegram
telegramSendMessage(
process.env.telegramDalleBotToken,
{ chat_id: chatId, text: `error: ${e}` },
);
// also throw so we can check in https://www.val.town/settings/evaluations
throw e;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export const telegramSendPhoto = async (botToken: string, options: {
chat_id: string | number;
message_thread_id?: number;
photo: string;
caption?: string;
parse_mode?: string;
caption_entities?: any[];
has_spoiler?: boolean;
disable_notification?: boolean;
protect_content?: boolean;
reply_to_message_id?: number;
allow_sending_without_reply?: boolean;
reply_markup?: any[];
}) =>
fetchJSON(
`https://api.telegram.org/bot${botToken}/sendPhoto`,
{
method: "POST",
body: JSON.stringify({ ...options }),
},
);

Message yourself on Telegram

Inspired by console.email, this val lets you send yourself Telegram messages via the Val Town Telegram Bot. You can use it to make custom Telegram bots, such as this DallE one.

Usage

@stevekrouse.telegram(@me.secrets.telegram, "hi to me on telegram!")
@me.t("hello telegram!")

Installation

It takes less than a minute to set up!

  1. Start a conversation with ValTownBot

  2. Copy the secret it gives you

  3. Save it in your Val Town secrets under telegram

  4. Send a message!

@stevekrouse.telegram(@me.secrets.telegram, "hi to me on telegram!")

Example: https://www.val.town/v/stevekrouse.exampleTelegramMessage

  1. (Bonus) Make a helper function

If you want to make it even easier to message yourself on telegram, ie @me.t("hello!") then you can setup a helper function:

Create vallet t = (message, options) => @stevekrouse.telegram(@me.secrets.telegram, message, options);

Ensure you keep this function private otherwise anyone can message you on Telegram!

Commands

  • /roll - Roll your secret in case you accidentally leak it.
  • /webhook - Set a webhook to receive messages you send to @ValTownBot

Receiving Messages

If you send /webhook to @ValTownBot, it will let you specify a webhook URL. It will then forward on any messages (that aren't recognized @ValTownBot commands) to that webhook. It's particularly useful for creating personal chatbots, like my telegram <-> DallE bot.

How it works

Telegram has a lovely API.

  1. I created a @ValTownBot via Bot Father.
  2. I created a webhook and registered it with telegram
  3. Whenever someone new messages @ValTownBot, I generate a secret and save it along with their Chat Id in @stevekrouse.telegramValTownBotSecrets (a private val), and message it back to them
  4. Now whenever you call this val, it calls telegramValTownBot via the Run API (api is a helper), which looks up your Chat Id via your secret and sends you a message

Telegram Resources

Credits

This val was originally made by pomdtr.

Readme
1
2
3
4
5
6
import { runVal } from "https://esm.town/v/std/runVal";
export async function telegram(secret: string, text: string, options?) {
return runVal("stevekrouse.telegramValTownBot", secret, text, options);
}
// Forked from @pomdtr.telegram
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import { feishuGetInteractiveMessage } from "https://esm.town/v/z233/feishuGetInteractiveMessage";
import { bebopBotFeishuWebhookUrl } from "https://esm.town/v/z233/bebopBotFeishuWebhookUrl";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
import { createFeishuCardActionElementBuilder } from "https://esm.town/v/z233/createFeishuCardActionElementBuilder";
import { createFeishuCardBuilder } from "https://esm.town/v/z233/createFeishuCardBuilder";
import { bebopBotSecretToken } from "https://esm.town/v/z233/bebopBotSecretToken";
export async function bebopBotWebhook(
req: express.Request,
res: express.Response
) {
const requestSecretToken =
req?.options?.headers?.["x-telegram-bot-api-secret-token"];
if (requestSecretToken !== bebopBotSecretToken) {
res.status(403).send("Access denied");
return;
}
const { channel_post: channelPost } = req.body;
if (!channelPost) {
res.send("ok");
return;
}
const {
text,
entities: textEntities,
caption,
caption_entities: captionEntities,
} = channelPost;
const entities = textEntities || captionEntities;
let textToSend = text || caption;
let accumOffset = 0;
for (const entry of entities) {
if (entry.type === "text_link") {
const { offset, length, url } = entry;
const entryStart = offset + accumOffset;
const mdUrl = getMarkdownLink(
textToSend.substring(entryStart, entryStart + length),
url
);
textToSend =
textToSend.substring(0, entryStart) +
mdUrl +
textToSend.substring(entryStart + length);
accumOffset = mdUrl.length - length;
}
}
const { forward_from_chat: fowardFromChat, reply_markup: replyMarkup } =
channelPost;
const cardBuilder = await createFeishuCardBuilder();
if (fowardFromChat) {
cardBuilder.setHeader({
template: "blue",
title: {
content: `Forwarded from ${fowardFromChat.title} @${fowardFromChat.username}`,
tag: "plain_text",
},
});
}
cardBuilder.addMarkdownElement(textToSend);
if (replyMarkup && replyMarkup.inline_keyboard?.length) {
const actionBuilder =
await createFeishuCardActionElementBuilder();
const { inline_keyboard: inlineKeyboard } = replyMarkup;
const markups = inlineKeyboard.flat();
markups.forEach((m) =>
actionBuilder.addAction({
tag: "button",
text: {
tag: "plain_text",
content: m.text,
},
type: "default",
url: m.url,
})
);
cardBuilder.addActionElement(actionBuilder.build());
}
const card = cardBuilder.build();
await fetchJSON(
bebopBotFeishuWebhookUrl,
{
method: "POST",
body: JSON.stringify(
await feishuGetInteractiveMessage({ card })
),
}
);
res.send("ok");
function getMarkdownLink(text, url) {
return `[${text}](${url})`;
}
}
3
Next