# How to send a Telegram message with curl

sendMessage in curl: chat_id, text, parse_mode, buttons, finding a chat_id and errors.

https://shiba-bank.com/en/guides/bot-api-curl

Updated 2026-10-02 · 5 min read

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](https://t.me/botfather) — [how to get it and keep it safe](https://shiba-bank.com/en/guides/bot-token).

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`, `MarkdownV2` or `Markdown`.
- `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:

1. Open your bot in Telegram and send it any message, such as `/start`.
2. Ask for updates: `curl "https://api.telegram.org/bot<TOKEN>/getUpdates"`.
3. In the reply find `message`, then `chat`, then the field `id` — that is your `chat_id`. For a public channel you can use its `@username` instead of a number.

`getUpdates` works only while the bot has no webhook set — see [getUpdates and webhooks](https://shiba-bank.com/en/guides/bot-api-updates). 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 `&lt;`, `&gt;` and `&amp;`. 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](https://shiba-bank.com/en/guides/bot-token).
- **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_id` has 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_after` field — 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.

> **Tip:** 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](https://shiba-bank.com/en/guides/bot-api-updates). If your program needs to send users Stars or Premium, the Shiba Bank bot has an API for that — see the [documentation](https://shiba-bank.com/api/docs).

## 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`.
