Como enviar mensagens pela API do Telegram com sendMessage (curl, Python e JavaScript)
Para enviar mensagem pela API do Telegram, faça um POST para https://api.telegram.org/bot<token>/sendMessage com dois campos: chat_id (para onde) e text (o quê). A resposta traz a mensagem enviada. Abaixo estão exemplos prontos em curl, Python e JavaScript, formatação com HTML e MarkdownV2, botões inline e os erros mais comuns.
Formato da requisição
A Bot API aceita GET e POST, com parâmetros na query string, em application/x-www-form-urlencoded, application/json ou multipart/form-data. Para texto, JSON é o mais prático. O sendMessage exige:
chat_id— id numérico do chat ou@nomedocanal;text— de 1 a 4096 caracteres depois do processamento das entidades.
Opcionais úteis: parse_mode, entities, link_preview_options, disable_notification, protect_content, reply_parameters, reply_markup e message_thread_id. Ainda sem token ou chat id? Veja como pegar o token do bot e como pegar o chat id.
Enviar mensagem: curl, Python e JavaScript
curl -X POST "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/sendMessage" \
-H "Content-Type: application/json" \
-d '{"chat_id": 123456789, "text": "Pedido #1024 confirmado!"}'
import os
import requests
TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
def enviar(chat_id, texto, **extra):
resp = requests.post(
f"https://api.telegram.org/bot{TOKEN}/sendMessage",
json={"chat_id": chat_id, "text": texto, **extra},
timeout=10,
)
data = resp.json()
if not data["ok"]:
raise RuntimeError(f"{data['error_code']}: {data['description']}")
return data["result"]
msg = enviar(123456789, "Olá do Python!")
print(msg["message_id"])
// Node.js 18+ (fetch nativo). Nunca use o token em código do navegador.
const token = process.env.TELEGRAM_BOT_TOKEN;
const resp = await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ chat_id: 123456789, text: "Olá do JavaScript!" }),
});
const data = await resp.json();
console.log(data.ok ? data.result.message_id : data.description);
Formatação: parse_mode HTML e MarkdownV2
Com "parse_mode": "HTML" você pode usar <b>, <strong>, <i>, <em>, <u>, <ins>, <s>, <strike>, <del>, <tg-spoiler> (ou <span class="tg-spoiler">), <a href>, <code>, <pre> e <blockquote> (inclusive <blockquote expandable>). Todo <, > e & que não faça parte de uma tag deve virar <, > e &.
{
"chat_id": 123456789,
"parse_mode": "HTML",
"text": "<b>Pedido #1024</b>\nTotal: <code>R$ 89,90</code>\nPreço < R$ 100 & frete grátis\n<a href=\"https://example.com\">Acompanhar</a>"
}
Com "parse_mode": "MarkdownV2", estes caracteres precisam de \ antes quando são texto comum: _ * [ ] ( ) ~ ` > # + - = | { } . ! (e a própria barra invertida). Um ponto final sem escape já gera Bad Request: can't parse entities. Função para escapar texto dinâmico:
import re
def escape_md2(texto: str) -> str:
return re.sub(r"([_*\[\]()~`>#+\-=|{}.!\\])", r"\\\1", texto)
enviar(123456789, "*Total:* " + escape_md2("R$ 89,90 (até 3x)."), parse_mode="MarkdownV2")
Existe ainda o modo legado Markdown, mantido só por compatibilidade.
Botões com teclado inline (reply_markup)
{
"chat_id": 123456789,
"text": "Escolha uma opção:",
"reply_markup": {
"inline_keyboard": [[
{"text": "Abrir site", "url": "https://example.com"},
{"text": "Confirmar", "callback_data": "confirmar_1024"}
]]
}
}
Botões url abrem um link; botões callback_data geram um update callback_query para o bot. O callback_data aceita de 1 a 64 bytes — letras acentuadas como “ç” e “ã” ocupam 2 bytes em UTF-8. Responda sempre com answerCallbackQuery, senão o botão fica com o ícone de carregamento. Para receber esses updates em produção, veja como configurar o webhook do bot.
Enviar para grupos, canais e tópicos
- Grupos: o bot precisa ser membro; use o id negativo (supergrupos começam com
-100). - Canais: o bot precisa ser administrador com permissão para publicar. Em canais públicos,
"chat_id": "@nomedocanal"funciona. - Tópicos de fórum: passe também o
message_thread_id.
Mensagem silenciosa e preview de links
{
"chat_id": 123456789,
"text": "Relatório diário: https://example.com/relatorio",
"disable_notification": true,
"protect_content": true,
"link_preview_options": {"is_disabled": true}
}
disable_notification entrega a notificação sem som; protect_content impede encaminhar e salvar. Em link_preview_options, em vez de desativar o preview, você pode escolher o url dele, usar prefer_small_media ou prefer_large_media e mostrá-lo acima do texto com show_above_text.
Erros comuns do sendMessage
| Erro | Causa e solução |
|---|---|
400 Bad Request: chat not found | chat id errado, usuário que nunca iniciou o bot ou bot fora do grupo/canal. |
403 Forbidden: bot was blocked by the user | o usuário bloqueou o bot; tire-o da sua lista de envio. |
400 Bad Request: can't parse entities | HTML inválido ou caractere sem escape no MarkdownV2. |
429 Too Many Requests: retry after N | limite excedido; espere parameters.retry_after segundos. |
401 Unauthorized | token inválido ou revogado. |
Tratamento simples do 429 em Python:
import time
def enviar_com_retry(payload):
while True:
data = requests.post(f"https://api.telegram.org/bot{TOKEN}/sendMessage",
json=payload, timeout=10).json()
if data["ok"] or data["error_code"] != 429:
return data
time.sleep(data["parameters"]["retry_after"])
Para não chegar lá: no máximo cerca de 1 mensagem por segundo no mesmo chat, 20 por minuto num grupo e uns 30 por segundo em envios em massa.
Teste no navegador
Abra o Bot API Tester no sendMessage, preencha chat_id, text, parse_mode e reply_markup e veja a resposta JSON na hora. A lista completa de parâmetros está na referência do método sendMessage (em inglês).
Perguntas frequentes
Como enviar mensagem para quem nunca falou com o bot?
Não é possível: bots não podem iniciar conversas. A pessoa precisa abrir o bot e tocar em Iniciar; depois disso você usa o id dela como chat_id.
Qual o limite de caracteres do sendMessage?
O text aceita de 1 a 4096 caracteres depois do processamento das entidades. Textos maiores precisam ser divididos em várias mensagens; legendas de mídia vão até 1024.
Quantas mensagens por segundo o bot pode enviar?
Evite mais de 1 por segundo no mesmo chat e mais de 20 por minuto num grupo; em envios em massa, cerca de 30 por segundo. Acima disso a API responde 429 com retry_after.
HTML ou MarkdownV2: qual usar?
Os dois funcionam. HTML costuma ser mais simples para texto dinâmico, porque só exige escapar <, > e &; no MarkdownV2 vários caracteres, como . e -, precisam de barra invertida.
Dá para enviar mensagem pela API do Telegram sem bot?
Pela Bot API, não: toda requisição usa o token de um bot criado no @BotFather. Enviar como usuário comum exige a API de clientes do Telegram (MTProto), que é outra API.
Guias relacionados
Como criar um bot no Telegram grátis: do BotFather à primeira mensagem
Aprenda a criar bot no Telegram grátis com o @BotFather: pegue o token, teste com getMe e envie a primeira mensagem com curl e Python.
Telegram bot token: como pegar o token do bot, verificar e revogar
Veja como pegar o token do bot do Telegram no @BotFather, achar o token de um bot existente, testar com getMe e revogar um token vazado.
Como configurar o webhook do bot do Telegram: setWebhook, secret_token e n8n
Configure o webhook do bot do Telegram: requisitos de HTTPS e portas, setWebhook com secret_token, getWebhookInfo, deleteWebhook e erros comuns no n8n.
Chat id do Telegram: como pegar o ID de usuário, grupo, canal e tópico com o seu bot
Descubra o chat id do Telegram para o seu bot: getUpdates em chat privado, grupos, supergrupos (-100), canais e tópicos, e o que fazer se vier vazio.