How to send a Telegram message with curl
How to send a Telegram message through the API with one curl request: sendMessage, chat_id, text, parse_mode, buttons, how to find a chat_id and what the 400, 403 and 429 errors mean.
You send a message through the Telegram API with the Bot API method sendMessage: it needs your bot's token, the recipient's chat_id and the text. From a command line it is one request: curl "https://api.telegram.org/bot<TOKEN>/sendMessage" --data-urlencode "chat_id=123456789" --data-urlencode "text=Hello". The reply is a JSON object with "ok": true and the sent message in result. The token comes from @BotFather — how to get it and keep it safe.
In the examples below <TOKEN> is a placeholder. Put your own token there, but never show it to anyone. The examples are written for bash and zsh.
What sendMessage needs
The request address is https://api.telegram.org/bot<TOKEN>/sendMessage. The method's parameters:
chat_id— required. The identifier of the chat, or the username of a channel in the format@channelusername.text— required. The message text, 1 to 4096 characters after entities are parsed.parse_mode— optional. The markup mode:HTML,MarkdownV2orMarkdown.reply_markup— optional. Buttons under the message or a custom keyboard.reply_parameters— reply to a specific message.disable_notification— send silently.link_preview_options— control link previews.
The method accepts both GET and POST. For text with spaces or non-Latin letters --data-urlencode is handier: curl encodes the value for you.
How to find a chat_id
As a rule a bot can't start a conversation: the person has to message it first, or add it to a group. So the order is:
- Open your bot in Telegram and send it any message, such as
/start. - Ask for updates:
curl "https://api.telegram.org/bot<TOKEN>/getUpdates". - In the reply find
message, thenchat, then the fieldid— that is yourchat_id. For a public channel you can use its@usernameinstead of a number.
getUpdates works only while the bot has no webhook set — see getUpdates and webhooks. A chat identifier is an integer that may not fit in 32 bits, so keep it in a 64-bit type in your code.
Request examples
A plain message: curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" --data-urlencode "chat_id=123456789" --data-urlencode "text=Your order is ready"
With HTML markup: curl -s "https://api.telegram.org/bot<TOKEN>/sendMessage" --data-urlencode "chat_id=123456789" --data-urlencode "parse_mode=HTML" --data-urlencode "text=<b>Your order</b> is ready"
In HTML mode, the characters <, > and & in ordinary text must be written as <, > and &. In MarkdownV2 the special characters are escaped with a backslash.
A message with a link button, sent as JSON: curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" -H "Content-Type: application/json" -d '{"chat_id": 123456789, "text": "Open the site", "reply_markup": {"inline_keyboard": [ [{"text": "Go", "url": "https://example.com"}] ]}}'
A JSON body works for every method except file uploads. A button under a message has text and either a url or callback_data (1 to 64 bytes): pressing the second kind sends the bot an event.
Errors
A failed request returns "ok": false with an error_code and a description. The usual ones:
- 401 Unauthorized. This usually means the token is wrong or has been replaced. Check it with
getMe— how. - 400 Bad Request: chat not found. The chat doesn't exist or the bot doesn't know it: the user has never written to the bot, or
chat_idhas a typo. - 403 Forbidden: bot was blocked by the user. The person blocked the bot, so nothing can be delivered to them.
- 400 about markup. Telegram couldn't parse the text: an HTML tag isn't closed, or
<,>and&aren't escaped. - 429 Too Many Requests. Requests are too frequent. The reply has a
retry_afterfield — how many seconds to wait before trying again.
The limits in Telegram's documentation: avoid sending more than one message per second to a single chat, a bot can send no more than 20 messages per minute to the same group, and a broadcast is limited to about 30 messages per second.
Don't write the token into scripts that end up in a repository: keep it in an environment variable or in a settings file outside the repository.
What next
To make the bot answer messages rather than only send them, set up receiving: getUpdates and webhooks. If your program needs to send users Stars or Premium, the Shiba Bank bot has an API for that — see the documentation.
Frequently asked questions
How do I send a message in Telegram through the API?
Call sendMessage with the bot's token, a chat_id and a text: curl "https://api.telegram.org/bot<TOKEN>/sendMessage" --data-urlencode "chat_id=<ID>" --data-urlencode "text=Hello".
How do I find the chat_id for sendMessage?
Send the bot any message and call getUpdates: the number is in message.chat.id. For a public channel you can use the channel's @username.
What does "chat not found" mean in Telegram?
The bot doesn't know that chat: either chat_id is wrong, or the person has never written to the bot. As a rule a bot can't start the conversation.
What does "bot was blocked by the user" mean?
It's a 403 error: the user blocked the bot, so you can't write to them.
Can I send a message from my own account instead of a bot?
Not with a token: requests made with a bot token are made by the bot, and the messages go out in its name.
How do I send a message to a channel through a bot?
Add the bot to the channel as an administrator and put the public channel's @username in chat_id.


