Skip to main content

Sending Telegram Interactive Messages via API

Send Telegram interactive messages — inline keyboards, custom reply keyboards, and reply highlights — over HTTPS from any backend.

Written by Tarek Khalil

Endpoint

POST https://app.octopods.io/api/v1/telegram/interactive

Note: Interactive messaging is an opt-in feature. If the endpoint returns 403 Forbidden, contact Octopods support to enable it on your account.

Important: Telegram requires the recipient to have an existing chat with your bot — you cannot use this endpoint to start a brand-new conversation with a Telegram user. Send to a destination_user_id you already have on file from a prior message.

Request body

Field

Type

Required

Description

destination_user_id

string

Yes

The Telegram chat ID of the recipient.

telegram_interactive_message

object

Yes

The structured interactive message. Shape varies by type — see below.

intercom_teammate_id

string

No

The ID of the teammate the sent message should be attributed to.

Shape of telegram_interactive_message

{
  "type": "<one of: reply_buttons | reply_keyboard | remove_reply_keyboard | highlight_reply>",
  "text": "Your message body — up to 4096 characters.",
  "reply_markup": { ... }
}

text is always required and is capped at 4096 characters. The shape of reply_markup depends on the type.

Type: reply_buttons (inline keyboard)

A row of tappable buttons attached under your message. Each button is either a URL link or an inline reply suggestion.

{
  "destination_user_id": "987654321",
  "telegram_interactive_message": {
    "type": "reply_buttons",
    "text": "Your order is ready. What would you like to do?",
    "reply_markup": {
      "inline_keyboard": [
        [
          { "text": "Track order", "url": "https://example.com/orders/1234" },
          { "text": "Suggest reply", "switch_inline_query_current_chat": "Reschedule please" }
        ]
      ]
    }
  }
}

  • inline_keyboard is an array of rows; each row is an array of button objects.

  • 1 to 6 buttons total across all rows.

  • Each button must have a text label and exactly one of two action fields: url for a public, reachable URL (a tg:// link is also accepted), or switch_inline_query_current_chat for the suggested reply text inserted into the user’s input box.

Type: reply_keyboard (custom keyboard)

Replaces the customer’s keyboard with up to 6 custom buttons. Useful for quick replies, contact requests, or location requests.

{
  "destination_user_id": "987654321",
  "telegram_interactive_message": {
    "type": "reply_keyboard",
    "text": "How can we help?",
    "reply_markup": {
      "one_time_keyboard": true,
      "keyboard": [
        [ { "text": "Track my order" } ],
        [ { "text": "Share my number", "request_contact":  true } ],
        [ { "text": "Share my place",  "request_location": true } ]
      ]
    }
  }
}

  • keyboard is an array of rows; each row is an array of button objects.

  • 1 to 6 buttons total across all rows.

  • Each button object must include text. To turn a button into a contact or location request, set request_contact: true or request_location: true instead of (or in addition to) plain text.

  • one_time_keyboard (optional, defaults to false) — when true, the keyboard hides after the customer taps a button.

Type: remove_reply_keyboard

Clears any custom keyboard that a previous interactive message put on the customer’s screen.

{
  "destination_user_id": "987654321",
  "telegram_interactive_message": {
    "type": "remove_reply_keyboard",
    "text": "Thanks — back to the standard keyboard.",
    "reply_markup": { "remove_keyboard": true }
  }
}

Type: highlight_reply

Pre-focuses the customer’s keyboard on a reply to your message, with an optional placeholder hint.

{
  "destination_user_id": "987654321",
  "telegram_interactive_message": {
    "type": "highlight_reply",
    "text": "How would you rate your experience today?",
    "reply_markup": {
      "force_reply": true,
      "input_field_placeholder": "Type your rating (1–5)"
    }
  }
}

  • force_reply must be true.

  • input_field_placeholder is optional and capped at 64 characters.

Full example

curl -X POST "https://app.octopods.io/api/v1/telegram/interactive" \
  -H "X-Octopods-Auth: YOUR_TELEGRAM_CHANNEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "destination_user_id": "987654321",
    "telegram_interactive_message": {
      "type": "reply_buttons",
      "text": "Did your package arrive?",
      "reply_markup": {
        "inline_keyboard": [
          [
            { "text": "Yes", "switch_inline_query_current_chat": "Yes, thanks" },
            { "text": "No",  "switch_inline_query_current_chat": "Not yet" }
          ]
        ]
      }
    }
  }'

Successful response

HTTP 201 Created:

{
  "request_id": "abc123…",
  "message_id": 98765,
  "channel_message_id": "provider-id-here"
}

  • message_id — Octopods’s record of the sent message.

  • channel_message_id — Telegram’s own message ID.

Error codes

Errors return HTTP 400 Bad Request with:

{ "request_id": "…", "error_code": N, "error": "…" }

Code

Meaning

Fix

1

A required argument is missing (e.g. destination_user_id, telegram_interactive_message, or a required field inside the message such as text or button label).

The error string names the missing field. Add it to the request.

4

The interactive type is not one of the allowed values, or a field has the wrong type.

Use one of reply_buttons, reply_keyboard, remove_reply_keyboard, highlight_reply.

5

Telegram returned an error or validation failed.

See the error field; common causes are too many buttons, button label missing, or an unreachable URL.

6

Deprecated API key.

Copy the current key from the Telegram channel settings screen.

A 403 Forbidden response means interactive messaging is not enabled for your account — contact Octopods support to enable it.

Note: Full details and recovery steps are in Troubleshooting Failed Proactive Messages.


What’s next

Did this answer your question?