Telegram Bot API
🌐 Português

Como enviar mensagens pela API do Telegram com sendMessage (curl, Python e JavaScript)

· 7 min de leitura

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:

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 &lt;, &gt; e &amp;.

{
  "chat_id": 123456789,
  "parse_mode": "HTML",
  "text": "<b>Pedido #1024</b>\nTotal: <code>R$ 89,90</code>\nPreço &lt; R$ 100 &amp; 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

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

ErroCausa e solução
400 Bad Request: chat not foundchat id errado, usuário que nunca iniciou o bot ou bot fora do grupo/canal.
403 Forbidden: bot was blocked by the usero usuário bloqueou o bot; tire-o da sua lista de envio.
400 Bad Request: can't parse entitiesHTML inválido ou caractere sem escape no MarkdownV2.
429 Too Many Requests: retry after Nlimite excedido; espere parameters.retry_after segundos.
401 Unauthorizedtoken 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.

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.