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.

Twitter 𝕏 keyword Alerts

Custom notifications for when you, your company, or anything you care about is mentioned on Twitter.

1. Authentication

You'll need a Twitter Bearer Token. Follow these instructions to get one.

Unfortunately it costs $100 / month to have a Basic Twitter Developer account. If you subscribe to Val Town Pro, I can let you "borrow" my token. Just comment on this val and I'll hook you up.

2. Query

Change the query variable for what you want to get notified for.

You can use Twitter's search operators to customize your query, for some collection of keywords, filtering out others, and much more!

3. Notification

Below I'm sending these mentions to a private channel in our company Discord, but you can customize that to whatever you want, @std/email, Slack, Telegram, whatever.

Readme
Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
import { twitterSearch } from "https://esm.town/v/stevekrouse/twitterSearch";
const query = "\"val.town\" OR \"val town\" -_ValTown_";
export async function twitterAlert({ lastRunAt }: Interval) {
const results = await twitterSearch({
query,
start_time: lastRunAt,
bearerToken: Deno.env.get("twitter"),
});
if (!results.length) return;
// format results
let content = results
.map(({ author_name, author_username, text, id }) => `https://fxtwitter.com/${author_username}/status/${id}`)
.join("\n");
// notify
await discordWebhook({
url: Deno.env.get("mentionsDiscord"),
content,
});
}
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
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
import axios from "npm:axios";
import formData from "npm:form-data";
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 }),
},
);
export async function telegramSendAudioMessage(chatId: string, audioData: Uint8Array, botToken: string): Promise<void> {
const url = `https://api.telegram.org/bot${botToken}/sendAudio`;
// Assuming FormData is available or correctly polyfilled
let data = new FormData();
data.append("chat_id", chatId);
// Directly use the Uint8Array with Blob constructor
data.append("audio", new Blob([audioData], { type: "audio/mpeg" }), "feedback.mpga");
try {
// Replace axios with Deno's fetch API, adapted for your setup
const response = await fetch(url, {
method: "POST",
body: data, // FormData instance directly as the body
// Headers are set automatically by the browser, so they're omitted here
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
console.log(result);
} catch (error) {
console.error("Error sending audio message:", error.message);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage?v=5";
export const telegramWebhookEchoMessage = async (req: Request) => {
// Verify this webhook came from our bot
if (
req.headers.get("x-telegram-bot-api-secret-token")
!== Deno.env.get("telegramWebhookSecret")
) {
return new Response("Not Allowed", { status: 401 });
}
// Echo back the user's message
const body = await req.json();
const text: string = body.message.text;
const chatId: number = body.message.chat.id;
await telegramSendMessage(
Deno.env.get("telegramBotToken"),
{ chat_id: chatId, text },
);
return Response.json("ok");
};

Twitter 𝕏 keyword Alerts

Custom notifications for when you, your company, or anything you care about is mentioned on Twitter.

1. Authentication

You'll need a Twitter Bearer Token. Follow these instructions to get one.

Unfortunately it costs $100 / month to have a Basic Twitter Developer account. If you subscribe to Val Town Pro, I can let you "borrow" my token. Just comment on this val and I'll hook you up.

2. Query

Change the query variable for what you want to get notified for.

You can use Twitter's search operators to customize your query, for some collection of keywords, filtering out others, and much more!

3. Notification

Below I'm sending these mentions to a private channel in our company Discord, but you can customize that to whatever you want, @std/email, Slack, Telegram, whatever.

Readme
Runs every 1 hrs
Fork
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
import { twitterSearch } from "https://esm.town/v/stevekrouse/twitterSearch";
const query = "\"val.town\" OR \"val town\" -_ValTown_";
export async function twitterAlert({ lastRunAt }: Interval) {
const results = await twitterSearch({
query,
start_time: lastRunAt,
bearerToken: Deno.env.get("twitter"),
});
if (!results.length) return;
// format results
let content = results
.map(({ author_name, author_username, text, id }) => `https://fxtwitter.com/${author_username}/status/${id}`)
.join("\n");
// notify
await discordWebhook({
url: Deno.env.get("mentionsDiscord"),
content,
});
}

Twitter 𝕏 keyword Alerts

Custom notifications for when you, your company, or anything you care about is mentioned on Twitter.

1. Authentication

You'll need a Twitter Bearer Token. Follow these instructions to get one.

Unfortunately it costs $100 / month to have a Basic Twitter Developer account. If you subscribe to Val Town Pro, I can let you "borrow" my token. Just comment on this val and I'll hook you up.

2. Query

Change the query variable for what you want to get notified for.

You can use Twitter's search operators to customize your query, for some collection of keywords, filtering out others, and much more!

3. Notification

Below I'm sending these mentions to a private channel in our company Discord, but you can customize that to whatever you want, @std/email, Slack, Telegram, whatever.

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
import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
import { twitterSearch } from "https://esm.town/v/stevekrouse/twitterSearch";
const query = "\"val.town\" OR \"val town\" -_ValTown_";
export async function twitterAlert({ lastRunAt }: Interval) {
const results = await twitterSearch({
query,
start_time: lastRunAt,
bearerToken: Deno.env.get("twitter"),
});
if (!results.length) return;
// format results
let content = results
.map(({ author_name, author_username, text, id }) => `https://fxtwitter.com/${author_username}/status/${id}`)
.join("\n");
// notify
await discordWebhook({
url: Deno.env.get("mentionsDiscord"),
content,
});
}
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
import { epicTvDiscounts } from "https://esm.town/v/marksteve/epicTvDiscounts";
import { getEpicTvProduct } from "https://esm.town/v/marksteve/getEpicTvProduct";
import { set } from "https://esm.town/v/std/set?v=11";
import { telegram } from "https://esm.town/v/stevekrouse/telegram?v=4";
export const checkEpicTvDiscounts = async (user: string, secret: string, watchList: {
url: string;
targetDiscount: number;
}[]) => {
for (let { url, targetDiscount } of watchList) {
const product = await getEpicTvProduct(url);
console.log({ product });
const discount = parseFloat(product.discount);
if (isNaN(discount)) {
console.log(`No discount for ${product.name}`);
continue;
}
if (epicTvDiscounts[url] === discount) {
console.log(`No discount change for ${product.name}`);
continue;
}
else {
epicTvDiscounts[url] = discount;
}
if (parseFloat(product.discount) < targetDiscount) {
console.log(`Target discount not met for ${product.name}`);
continue;
}
telegram(
secret,
`${product.name} is ${product.discount} off!\n${product.oldPrice} ➡️ ${product.price}`,
);
}
await set("epicTvDiscounts", epicTvDiscounts);
return epicTvDiscounts;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage?v=5";
export const telegramWebhookEchoMessage = async (req: Request) => {
// Verify this webhook came from our bot
if (
req.headers.get("x-telegram-bot-api-secret-token")
!== Deno.env.get("telegramWebhookSecret")
) {
return new Response(undefined, { status: 401 });
}
// Echo back the user's message
const body = await req.json();
const text: string = body.message.text;
const chatId: number = body.message.chat.id;
await telegramSendMessage(
Deno.env.get("telegramBotToken"),
{ chat_id: chatId, text },
);
return Response.json("ok");
};

I never actually tried this out, but I think it or something like it should work based on the docs found here: https://telegram-bot-sdk.readme.io/reference/removewebhook

Readme
1
2
3
4
5
6
7
import { telegramSetWebhook } from "https://esm.town/v/stevekrouse/telegramSetWebhook";
console.log(
await telegramSetWebhook(Deno.env.get("telegramBotToken"), {
remove: true,
}),
);
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
98
99
100
export let date_me_docs_cache = [{
"Name": "Kamil",
"Profile": "https://docs.google.com/document/d/1kQgNZ7ikgKAxyxbsLSC2bBhXQgxv6Em340-ht5R5sjo/edit?usp=sharing",
"Gender": ["M"],
"Age": "24",
"Contact": "postreduxx gmail",
"LastUpdated": "2023-10-19T12:50:00.000Z",
"InterestedIn": ["M"],
"Location": ["Central Europe"],
"Style": ["mono"],
"LocationFlexibility": "Some",
"Community": ["Rationalism"],
}, {
"Name": "Zak Kallenborn",
"Profile": "zkallenborn.com/dateme",
"Gender": ["M"],
"Age": "33",
"Contact": "zkallenborn@gmail.com",
"LastUpdated": "2023-10-18T04:22:00.000Z",
"InterestedIn": ["F"],
"Location": ["DC"],
"Style": ["mono"],
"LocationFlexibility": "Some",
"Community": ["Tech", "EA"],
}, {
"Name": "Frazer Kirkman",
"Profile": "https://www.okcupid.com/profile/frazerkirkman",
"Gender": ["M"],
"Age": "44",
"Contact": "Frazerkirkman@gmail.com",
"LastUpdated": "2023-10-16T20:02:00.000Z",
"InterestedIn": ["F"],
"Location": ["San Francisco Bay Area"],
"Style": ["poly"],
"LocationFlexibility": "Some",
"Community": ["Tech", "Rationalism", "EA"],
}, {
"Name": "Mitchell Reynolds",
"Profile": "https://tundra-shell-d74.notion.site/Mitchell-s-Date-Me-Doc-9325999704f347a4b2515df774b3c7ff",
"Gender": ["M"],
"Age": "32",
"Contact": "https://www.facebook.com/mitchellsreynolds/",
"LastUpdated": "2023-10-14T06:43:00.000Z",
"InterestedIn": ["F"],
"Location": ["San Francisco Bay Area", "Berkeley"],
"Style": ["mono"],
"LocationFlexibility": "Flexible",
"Community": ["EA"],
}, {
"Name": "Sarah Hirner",
"Profile": "https://docs.google.com/document/d/1b3ZmRGXVfqiI9qcU55opVSxzDOFW5PYUNB_GUncbuZ0/edit?usp=sharing",
"Gender": ["F"],
"Age": "33",
"Contact": "shirner244@gmail.com",
"LastUpdated": "2023-10-13T18:05:00.000Z",
"InterestedIn": ["M"],
"Location": ["MA"],
"Style": ["mono"],
"LocationFlexibility": "None",
"Community": ["EA"],
}, {
"Name": "Marta",
"Profile": "https://martakrzeminska.notion.site/Date-Me-17435416720c439b8d6725d690808f55?pvs=4",
"Gender": ["F"],
"Age": "35",
"Contact": "SoYouWantToDateMarta[at]gmail[dot]com ",
"LastUpdated": "2023-10-11T10:18:00.000Z",
"InterestedIn": ["M"],
"Location": ["Central Europe"],
"Style": ["poly"],
"LocationFlexibility": "Flexible",
"Community": ["EA", "Rationalism", "Tech"],
}, {
"Name": "Vasco Grilo",
"Profile": "https://www.okcupid.com/profile/12671992320363212181/photos",
"Gender": ["M"],
"Age": "25",
"Contact": "+351918368684",
"LastUpdated": "2023-10-10T22:02:00.000Z",
"InterestedIn": ["F"],
"Location": ["Central Europe"],
"Style": ["mono"],
"LocationFlexibility": "Some",
"Community": ["EA"],
}, {
"Name": "David",
"Profile": "https://docs.google.com/document/d/1vhHtWBS-tS0bYamYxqr8KJNo6gxjE_0Kbzd6SsVt9ws/edit?usp=sharing",
"Gender": ["M"],
"Age": "34",
"Contact": "see doc",
"LastUpdated": "2023-10-10T18:27:00.000Z",
"InterestedIn": ["F", "M", "NB"],
"Location": ["London"],
"Style": ["mono", "poly"],
"LocationFlexibility": "Some",
"Community": ["Rationalism", "EA"],
}, {
"Name": "Jacques",
"Profile": "https://jacquesthibodeau.com/lets-go-on-a-date/",
"Gender": ["M"],

Bluesky keyword alerts

Custom notifications for when you, your company, or anything you care about is mentioned on Bluesky.

1. Query

Specify your queries in the queries variable.

Bluesky doesn't support boolean OR yet so we do a separate search for each keyword.

2. Notification

Below I'm sending these mentions to a private channel in our company Discord, but you can customize that to whatever you want, @std/email, Slack, Telegram, whatever.

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
import { blob } from "https://esm.town/v/std/blob";
import { discordWebhook } from "https://esm.town/v/stevekrouse/discordWebhook";
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
import { searchBlueskyPosts } from "https://esm.town/v/stevekrouse/searchBlueskyPosts";
const encounteredIDs_KEY = "bluesky_encounteredIDs";
const queries = ["val town", "val.town"];
export const blueskyAlert = async () => {
let posts = (await Promise.all(queries.map(searchBlueskyPosts))).flat();
// filter for new posts
let encounteredIDs = await blob.getJSON(encounteredIDs_KEY) ?? [];
let newPosts = posts.filter((post) => !encounteredIDs.includes(post.tid));
await blob.setJSON(encounteredIDs_KEY, [
...encounteredIDs,
...newPosts.map((post) => post.tid),
]);
if (newPosts.length === 0) return;
// format
const content = posts.map(
post => `https://bsky.app/profile/${post.user.handle}/post/${post.tid.split("/")[1]}`,
).join(
"\n",
);
// notify
await discordWebhook({
url: Deno.env.get("mentionsDiscord"),
content,
});
return newPosts;
};
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
import { blob } from "https://esm.town/v/std/blob";
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage?v=5";
import process from "node:process";
const DB_KEY = "telegram_Chotillo";
const LS = "/ls";
const X = "/x";
const X_ = X + " ";
const initBlob = async () => {
let exist = await blob.getJSON(DB_KEY);
if (!exist) {
await blob.setJSON(DB_KEY, []);
exist = [];
}
return exist;
};
const send = async (chatId: number, msg: string) => {
await telegramSendMessage(
process.env.telegramBotToken,
{ chat_id: chatId, text: msg },
);
};
export const telegramWebhookEchoMessage = async (req: Request) => {
const db: string[] = await initBlob();
// Verify this webhook came from our bot
if (
req.headers.get("x-telegram-bot-api-secret-token")
!== process.env.telegramWebhookSecret
) {
return new Response(undefined, { status: 401 });
}
// Echo back the user's message
const body = await req.json();
const text: string = body.message.text;
const chatId: number = body.message.chat.id;
if (text.startsWith(LS)) {
await send(chatId, db.join("\n"));
return Response.json("ok");
}
if (!text.startsWith(X_)) {
return Response.json("ok");
}
const cmd = text.split(X_)[1];
await blob.setJSON(DB_KEY, [...db, cmd]);
await send(chatId, `Processed ${cmd.length} bytes!`);
return Response.json("ok");
};
1
2
3
4
5
6
import { telegramGetMe } from "https://esm.town/v/vtdocs/telegramGetMe";
import process from "node:process";
export const getMeExample = telegramGetMe(
process.env.telegramBotToken,
);

Telegram to DallE Bot

Set up

  1. First you'll need to set yourself up to send and receive messages on Telegram. Follow all 5 steps here: https://www.val.town/v/stevekrouse.telegram

  2. Fork this @telegramBotHandler val below. Make sure you click Run to save it to your account.

  3. On your forked val, click the ⋮ menu > Endpoints > Copy express endpoint

  4. Message @ValTownBot /webhook

  5. Message @ValTownBot the express endpoint you copied

  6. You'll also need an openai key in your secrets for this particular DallE bot to work

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
import { t } from "https://esm.town/v/stevekrouse/t";
import { textToImageDalle } from "https://esm.town/v/stevekrouse/textToImageDalle";
import process from "node:process";
export async function telegramBotHandler(req, res) {
let text = req.body.message.text;
res.status(200).send("{}");
if (text.startsWith("/dalle")) {
await t("Loading...");
try {
let resp = await textToImageDalle(
process.env.openai,
text.replace("/dalle", ""),
1,
"1024x1024",
);
if ("error" in resp)
return t("DallE Error: " + resp.error.message);
else
return t(null, { photo: resp.data[0].url });
}
catch (e) {
// report any errors via telegram
await t("Error: " + e.message);
// also throw so we can check in https://www.val.town/settings/evaluations
throw e;
}
// Forked from @hootz.telegramDalleBot
} else if (text.startsWith("/gpt")) {
await t("hi");
}
else {
await t("Unkown command: " + text);
}
}
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
98
99
100
export const theme = {
semanticTokens: {
colors: {
"chakra-body-text": {
_light: "gray.800",
_dark: "whiteAlpha.900",
},
"chakra-body-bg": {
_light: "white",
_dark: "gray.800",
},
"chakra-border-color": {
_light: "gray.200",
_dark: "whiteAlpha.300",
},
"chakra-subtle-bg": {
_light: "gray.100",
_dark: "gray.700",
},
"chakra-placeholder-color": {
_light: "gray.500",
_dark: "whiteAlpha.400",
},
},
},
direction: "ltr",
breakpoints: {
base: "0em",
sm: "30em",
md: "48em",
lg: "62em",
xl: "80em",
"2xl": "96em",
},
zIndices: {
hide: -1,
auto: "auto",
base: 0,
docked: 10,
dropdown: 1000,
sticky: 1100,
banner: 1200,
overlay: 1300,
modal: 1400,
popover: 1500,
skipLink: 1600,
toast: 1700,
tooltip: 1800,
},
radii: {
none: "0",
sm: "0.125rem",
base: "0.25rem",
md: "0.375rem",
lg: "0.5rem",
xl: "0.75rem",
"2xl": "1rem",
"3xl": "1.5rem",
full: "9999px",
},
blur: {
none: 0,
sm: "4px",
base: "8px",
md: "12px",
lg: "16px",
xl: "24px",
"2xl": "40px",
"3xl": "64px",
},
colors: {
transparent: "transparent",
current: "currentColor",
black: "#000000",
white: "#FFFFFF",
whiteAlpha: {
"50": "rgba(255, 255, 255, 0.04)",
"100": "rgba(255, 255, 255, 0.06)",
"200": "rgba(255, 255, 255, 0.08)",
"300": "rgba(255, 255, 255, 0.16)",
"400": "rgba(255, 255, 255, 0.24)",
"500": "rgba(255, 255, 255, 0.36)",
"600": "rgba(255, 255, 255, 0.48)",
"700": "rgba(255, 255, 255, 0.64)",
"800": "rgba(255, 255, 255, 0.80)",
"900": "rgba(255, 255, 255, 0.92)",
},
blackAlpha: {
"50": "rgba(0, 0, 0, 0.04)",
"100": "rgba(0, 0, 0, 0.06)",
"200": "rgba(0, 0, 0, 0.08)",
"300": "rgba(0, 0, 0, 0.16)",
"400": "rgba(0, 0, 0, 0.24)",
"500": "rgba(0, 0, 0, 0.36)",
"600": "rgba(0, 0, 0, 0.48)",
"700": "rgba(0, 0, 0, 0.64)",
"800": "rgba(0, 0, 0, 0.80)",
"900": "rgba(0, 0, 0, 0.92)",
},
gray: {

Usage in bash:

# Can be in .bashrc or .zsrhc:
to-tg() {
  local input=""

  if [[ -p /dev/stdin ]]; then
    input="$(cat -)"
  else
    input="${@}"
  fi

  if [[ -z "${input}" ]]; then
    return 1
  fi

  local chat_id="-1001826545120" # Set chat_id where your bot is
  local message="$input"

  curl -G https://api.val.town/v1/run/dpetrouk.notifyInTg --data-urlencode 'args=["'"$chat_id"'", "'"$message"'"]'
}
# You will get notification where command is succesfully finished
<command in bash> && to-tg Success
# Can be like that?
<command in bash> | to-tg Success
Readme
1
2
3
4
5
6
7
8
9
10
import process from "node:process";
import { telegramSendMessage } from "https://esm.town/v/vtdocs/telegramSendMessage?v=5";
export async function notifyInTg(chatId, text) {
telegramSendMessage(
process.env.telegramBotToken,
{ chat_id: chatId, text },
);
return `Sent message '${text}' to Telegram chat ${chatId}`;
}