Dialog Bot API
Dialog has HTTP bot API. A bot is a Dialog
account you own, driven by an external program that holds a secret token. Your program calls an
HTTP API to send messages, and receives incoming messages by long-polling
(getUpdates) or via a signed webhook. If you've used the Telegram
Bot API, this will feel immediately familiar.
Base URL: https://dialogmsg.xyz
· Everything is a bot user (DMable, addable to groups).
· Inline keyboards & callback_query are supported.
1. Create a bot
Bots are self-serve — no approval needed.
- Open Dialog → Settings (gear) → Developer.
- Click New bot, enter a display name and a
username (
3–24chars,a–z 0–9 _; ending in_botis a nice convention). - You'll get a token like
dlg_XXXXXXXXXXXXXXXXXXXXXXXX. Copy it now — it is shown only once. - The same pane lets you set commands, a webhook, and group privacy, or regenerate the token / delete the bot.
2. Authentication
Pass the token one of two ways:
# A) Token in the path (point any Telegram library's base URL here):
curl https://dialogmsg.xyz/bot<token>/getMe
# B) Bearer header, via the /api/bot/<method> route:
curl https://dialogmsg.xyz/api/bot/getMe -H "Authorization: Bearer <token>"
Parameters may be sent as a JSON body (Content-Type: application/json)
or as a query string — the JSON body wins on conflict. Every
response is { "ok": true, "result": … } or
{ "ok": false, "error_code": …, "description": … }.
3. chat_id — how chats are addressed
| Chat | Format | Example |
|---|---|---|
| Direct message | @dm:<a>~<b> — the two logins sorted alphabetically | @dm:demo_bot~vnx |
| Group | @grp:<id> | @grp:8f3a1c |
Usually you just read chat.id off an incoming update and reply to it. A bot can
only send to a chat it participates in, otherwise sendMessage returns 403.
4. Receiving messages
Option A — getUpdates (long-polling)
curl "https://dialogmsg.xyz/bot<token>/getUpdates?offset=0&timeout=30"
offset— pass<highest update_id handled> + 1to acknowledge everything below it (acknowledged updates are deleted). Start at0.timeout— seconds to hold the connection open (0–30). Use ~30for efficient polling.limit— max updates to return (default100).
Option B — Webhook
curl -X POST "https://dialogmsg.xyz/bot<token>/setWebhook" \
-H 'Content-Type: application/json' \
-d '{"url":"https://your.app/dialog/hook","secret":"my-shared-secret"}'
- URL must be HTTPS + a public host (loopback / private ranges rejected — SSRF guard).
- Each delivery is signed: header
X-Dialog-Signature: sha256=<hex>wherehex = HMAC_SHA256(secret, rawBody). Verify it before trusting the payload. - While a webhook is set, updates go to it and are not queued for
getUpdates. Failed deliveries are dropped (no retry in v1).
5. Sending & managing messages
curl -X POST "https://dialogmsg.xyz/bot<token>/sendMessage" \
-H 'Content-Type: application/json' \
-d '{"chat_id":"@dm:demo_bot~vnx","text":"Hello 👋"}'
Media methods — sendPhoto / sendVideo / sendAudio /
sendDocument — take the media as a data: URL or a public
https: URL (field name any of media, photo,
document, video, audio, url), plus optional
caption and filename. Max 75 MB. You can also
editMessageText and deleteMessage your own messages, and send a typing
indicator with sendChatAction.
5b. Inline buttons (keyboards)
Attach an inline keyboard to any message with reply_markup (Telegram-shaped) — a
list of rows, each a list of buttons. A button is a link
(url, opens in the user's browser) or a callback
(callback_data, ≤ 64 chars). Works on sendMessage and the media
methods, and channel webhooks accept the same buttons field.
curl -X POST ".../sendMessage" -H 'Content-Type: application/json' -d '{
"chat_id": "@dm:demo_bot~vnx",
"text": "Pick one:",
"reply_markup": { "inline_keyboard": [
[ {"text":"👍 Yes","callback_data":"yes"}, {"text":"👎 No","callback_data":"no"} ],
[ {"text":"Open site","url":"https://dialogmsg.xyz"} ]
] }
}'
When a user taps a callback button you receive a callback_query update (see below).
Acknowledge it with answerCallbackQuery (optionally showing a toast/alert), and
swap the keyboard or text with editMessageReplyMarkup / editMessageText.
// on a callback_query update:
await call("answerCallbackQuery", { callback_query_id: q.id, text: "You chose " + q.data });
await call("editMessageReplyMarkup", { message_id: q.message.message_id, reply_markup: { inline_keyboard: [] } });
6. The update object
Each item from getUpdates (and each webhook POST body) looks like:
{
"update_id": 137,
"message": {
"message_id": 684,
"from": { "login": "vnx", "name": "Vanylix", "is_bot": false },
"chat": { "id": "@dm:demo_bot~vnx", "type": "private" },
"date": 1783923794,
"text": "/start",
"media_type": "image",
"media": "https://…",
"media_name": "cat.png"
}
}
chat.type is "private" or "group". text is
present for text; media_type ∈ image · video · audio · file for media.
update_id is the acknowledgement cursor for getUpdates.
A button tap arrives as a callback_query update instead of a message:
{
"update_id": 140,
"callback_query": {
"id": "a1b2c3…",
"from": { "login": "vnx", "name": "Vanylix", "is_bot": false },
"message": { "message_id": 684, "chat": { "id": "@dm:demo_bot~vnx", "type": "private" } },
"data": "yes"
}
}
7. Commands
Register slash-commands — they power the / command menu that appears in the composer when a user chats with your bot.
curl -X POST .../setMyCommands -H 'Content-Type: application/json' -d '{
"commands": [
{ "command": "start", "description": "Say hello" },
{ "command": "ping", "description": "Check the bot is alive" }
]
}'
8. Behavior in groups — privacy
Bots are added to groups through the normal member picker. By default a bot has
group privacy ON: inside a group it only receives messages that start with a
slash command (/…) or @mention the bot. Turn privacy off
to receive every group message. Privacy never affects DMs.
9. Method reference
| Method | Params | Result |
|---|---|---|
getMe | — | bot identity |
getMyCommands | — | [{command, description}] |
setMyCommands | commands | true |
setWebhook | url, secret? | true |
deleteWebhook | — | true |
getUpdates | offset?, limit?, timeout? | [update, …] |
sendMessage | chat_id, text, reply_markup? | sent message |
sendPhoto / Video / Audio / Document | chat_id, media, caption?, filename?, reply_markup? | sent message |
editMessageText | message_id, text, reply_markup? | true |
editMessageReplyMarkup | message_id, reply_markup | true |
answerCallbackQuery | callback_query_id, text?, show_alert? | true |
deleteMessage | message_id | true |
sendChatAction | chat_id, action | true |
10. Example — a polling echo bot (Node.js, zero deps)
const TOKEN = process.env.DIALOG_TOKEN; // dlg_…
const BASE = `https://dialogmsg.xyz/bot${TOKEN}`;
async function call(method, params = {}) {
const r = await fetch(`${BASE}/${method}`, {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify(params),
});
return r.json();
}
let offset = 0;
await call("setMyCommands", { commands: [{ command: "start", description: "Say hi" }] });
while (true) {
const { result: updates } = await call("getUpdates", { offset, timeout: 30 });
for (const u of updates) {
offset = u.update_id + 1;
const msg = u.message;
if (!msg?.text) continue;
const reply = msg.text === "/start" ? "👋 Hi!" : `You said: ${msg.text}`;
await call("sendMessage", { chat_id: msg.chat.id, text: reply });
}
}
Run: DIALOG_TOKEN=dlg_… node bot.mjs (Node 18+ for built-in
fetch). The full webhook example and every detail live in the
Markdown reference on GitHub.
↑ A real bot built on this API in ~90 lines — see the polling example above.