Cliqtel
  • 製品
    インフラ
    バーチャル番号70カ国以上のローカル・モバイル・フリーダイヤル SIP トランクあらゆる PBX に対応するキャリアグレード SIP 旅行データ(eSIM)200以上の国でモバイルデータ、ローミング料なし
    コミュニケーション
    メッセージング双方向 SMS と WhatsApp テンプレート クラウド電話システムビジュアルコールフロー、IVR、キュー、CRM ポップ コンタクトセンター高度なルーティングと AI — アーリーアクセス
    パートナー & AI
    Cliqtel ConnectMSP 向けホワイトラベルプラットフォーム AI アクセス (MCP)エージェントとコパイロット向けの AI 操作可能なテレコム
  • ソリューション
    チーム別
    リモートチーム分散チームにひとつのビジネス番号 サポートチームサポート向けのキュー、IVR、共有インボックス 営業チームクリックトゥコール、CRM ポップ、ローカル発信者番号
    探す
    対応エリア70カ国以上の番号と料金 連携PBX、CRM、各種ツールを接続
  • 料金
    料金とプラン
    料金番号ごと・利用量ごとの透明な料金 対応エリアと料金国別の通話料金と番号料金 バンドルプリペイドの番号 + 分数バンドル
  • ドキュメント
    はじめる
    はじめにアカウントと最初の番号を設定 API リファレンス番号・通話・メッセージング向け REST API コールフローIVR とルーティングをビジュアルに構築 ヘルプセンターFAQ、ガイド、トラブルシューティング
    ガイド
    PBX & SIP セットアップ3CX、FreePBX、Asterisk、Teams を接続 メッセージングガイドSMS と WhatsApp の連携ガイド 規制対応国別の番号登録ルール
  • 会社情報
    会社
    Cliqtel について私たちは何者で、何を作っているのか お問い合わせ営業またはサポートチームにご相談ください パートナーCliqtel のパートナー・リセラーになる
    リソース
    ブログ製品ニュースとテレコムガイド ステータスプラットフォームとネットワークのリアルタイム状況 連携PBX、CRM、各種ツールのマーケットプレイス
English EN Nederlands NL Deutsch DE Français FR Español ES Português PT العربية AR 中文 ZH 日本語 JA हिन्दी HI
ログイン 番号を注文
Cliqtel
製品 バーチャル番号70カ国以上のローカル・モバイル・フリーダイヤル SIP トランクあらゆる PBX に対応するキャリアグレード SIP 旅行データ(eSIM)200以上の国でモバイルデータ、ローミング料なし メッセージング双方向 SMS と WhatsApp テンプレート クラウド電話システムビジュアルコールフロー、IVR、キュー、CRM ポップ コンタクトセンター高度なルーティングと AI — アーリーアクセス Cliqtel ConnectMSP 向けホワイトラベルプラットフォーム AI アクセス (MCP)エージェントとコパイロット向けの AI 操作可能なテレコム
ソリューション リモートチーム分散チームにひとつのビジネス番号 サポートチームサポート向けのキュー、IVR、共有インボックス 営業チームクリックトゥコール、CRM ポップ、ローカル発信者番号 対応エリア70カ国以上の番号と料金 連携PBX、CRM、各種ツールを接続
料金 料金番号ごと・利用量ごとの透明な料金 対応エリアと料金国別の通話料金と番号料金 バンドルプリペイドの番号 + 分数バンドル
ドキュメント はじめにアカウントと最初の番号を設定 API リファレンス番号・通話・メッセージング向け REST API コールフローIVR とルーティングをビジュアルに構築 ヘルプセンターFAQ、ガイド、トラブルシューティング PBX & SIP セットアップ3CX、FreePBX、Asterisk、Teams を接続 メッセージングガイドSMS と WhatsApp の連携ガイド 規制対応国別の番号登録ルール
会社情報 Cliqtel について私たちは何者で、何を作っているのか お問い合わせ営業またはサポートチームにご相談ください パートナーCliqtel のパートナー・リセラーになる ブログ製品ニュースとテレコムガイド ステータスプラットフォームとネットワークのリアルタイム状況 連携PBX、CRM、各種ツールのマーケットプレイス

言語
EN NL DE FR ES PT AR ZH JA HI
ログイン 無料ではじめる
← Help Center
On this page
Overview The 24-Hour Window Prerequisites Media Messages Location Messages Interactive: Reply Buttons Interactive: List Menus Delivery Status Best Practices FAQ

Rich WhatsApp Messages — Media, Location & Interactive

Messaging · 10 min read Messaging WhatsApp API
What this guide covers: How to send rich WhatsApp messages through the Cliqtel messaging API — images, videos and documents; pin-drop locations; and interactive reply buttons and list menus. Every example uses a single endpoint and switches behaviour with the type field.

Overview

All WhatsApp messages are sent to one endpoint:

ENDPOINT
POST https://cliqtel.com/api/v1/whatsapp/messages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

The API key must carry the whatsapp:write scope, and the endpoint is rate limited to 60 requests per minute. Every request includes two common fields:

  • account_id — an integer, your WhatsApp account id. Fetch it from GET /api/v1/whatsapp/accounts.
  • to — the recipient in E.164 format, e.g. "+31611398058".

The type field selects the kind of message you're sending:

TypeWhat it sendsTypical use
templatePre-approved Meta templateFirst contact / outside the 24h window
textFree-form text (up to 4096 chars)Replies inside the 24h window
mediaImage, video or documentReceipts, brochures, product images
locationA pin on the mapSharing a store or branch
interactiveReply buttons or a list menuQuick confirmations, menu choices
Response shape: On success the API returns the Cliqtel message id and a status, e.g. { "id": 90218, "status": "accepted" }. Use the id to correlate delivery status webhooks (see below).

The 24-Hour Window

WhatsApp only allows free-form messages inside a customer service window — the 24 hours following the customer's most recent message to you. Templates are how you re-open a conversation.

Free-form requires an open window. The text, media, location and interactive types only deliver within 24 hours of the customer's last inbound message. Outside that window your only option is a pre-approved template. A free-form send to a contact with no open window will be rejected by WhatsApp.

A practical pattern: send a template to start (or restart) the conversation, and once the customer replies you have a fresh 24-hour window in which the rich message types below work freely.

Prerequisites

  • A WhatsApp Business Account connected to Cliqtel (setup guide)
  • A Cliqtel API key with the whatsapp:write scope (Dashboard → API Keys)
  • Your account id from GET /api/v1/whatsapp/accounts
  • For media: an uploaded media id (upload via the portal or the media API)
  • An open 24-hour window with the recipient (or a template to open one)

Media Messages

Media messages send an image, video or document. The file is referenced by an uploaded media id — upload it through the portal or the media API first, then reference the returned id here. Where supported you can also send media by link instead of an id. A caption is optional; filename applies to documents so the recipient sees a friendly name.

Common uses: sending a customer their receipt or invoice as a PDF, a product brochure, or product images during a sales chat.

NODE.JS — SEND AN IMAGE WITH CAPTION
const response = await fetch('https://cliqtel.com/api/v1/whatsapp/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    account_id: 1,                    // Your WhatsApp account ID
    to: '+31611398058',
    type: 'media',
    media: {
      type: 'image',                  // image | video | document
      id: '',      // from the portal or media API
      caption: 'Here is your product preview',
    },
  }),
});

const data = await response.json();
console.log(data.id, data.status);    // message ID, "accepted"
PYTHON — SEND A DOCUMENT (RECEIPT)
import requests

resp = requests.post(
    'https://cliqtel.com/api/v1/whatsapp/messages',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'account_id': 1,
        'to': '+31611398058',
        'type': 'media',
        'media': {
            'type': 'document',          # image | video | document
            'id': '',
            'caption': 'Your receipt',
            'filename': 'receipt-90218.pdf',  # documents only
        },
    },
)

print(resp.json()['id'], resp.json()['status'])
Which field? Set media.type to image, video or document. caption is optional for all three; filename is only used for documents.

Location Messages

A location message drops a pin on the recipient's map with an optional name and address label. Use it to share the location of a store, branch or pickup point — the customer can tap through to their maps app for directions.

NODE.JS — SHARE A LOCATION
const response = await fetch('https://cliqtel.com/api/v1/whatsapp/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    account_id: 1,
    to: '+31611398058',
    type: 'location',
    location: {
      latitude: 38.72,
      longitude: -9.14,
      name: 'Cliqtel HQ',
      address: 'Zeist, The Netherlands',
    },
  }),
});

const data = await response.json();
console.log(data.id, data.status);
PYTHON
import requests

resp = requests.post(
    'https://cliqtel.com/api/v1/whatsapp/messages',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'account_id': 1,
        'to': '+31611398058',
        'type': 'location',
        'location': {
            'latitude': 38.72,
            'longitude': -9.14,
            'name': 'Cliqtel HQ',
            'address': 'Zeist, The Netherlands',
        },
    },
)

print(resp.json()['id'], resp.json()['status'])

Interactive: Reply Buttons

Reply buttons show up to three tappable buttons under your message. When the customer taps one, WhatsApp sends you an inbound message carrying the button's id — ideal for quick confirmations like Yes / No or a short set of choices.

Set interactive.type to "button". The action.buttons array holds each button as a reply with an id (returned to you on tap) and a title (shown to the user). Header, body and footer text are optional — body is recommended.

NODE.JS — YES / NO CONFIRMATION
const response = await fetch('https://cliqtel.com/api/v1/whatsapp/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    account_id: 1,
    to: '+31611398058',
    type: 'interactive',
    interactive: {
      type: 'button',
      body: { text: 'Confirm your appointment for tomorrow at 14:00?' },
      footer: { text: 'Cliqtel Support' },
      action: {
        buttons: [
          { type: 'reply', reply: { id: 'confirm_yes', title: 'Yes' } },
          { type: 'reply', reply: { id: 'confirm_no',  title: 'No' } },
        ],
      },
    },
  }),
});

const data = await response.json();
console.log(data.id, data.status);
PYTHON
import requests

resp = requests.post(
    'https://cliqtel.com/api/v1/whatsapp/messages',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'account_id': 1,
        'to': '+31611398058',
        'type': 'interactive',
        'interactive': {
            'type': 'button',
            'body': {'text': 'Confirm your appointment for tomorrow at 14:00?'},
            'footer': {'text': 'Cliqtel Support'},
            'action': {
                'buttons': [
                    {'type': 'reply', 'reply': {'id': 'confirm_yes', 'title': 'Yes'}},
                    {'type': 'reply', 'reply': {'id': 'confirm_no',  'title': 'No'}},
                ],
            },
        },
    },
)

print(resp.json()['id'], resp.json()['status'])
Reading the tap: The button id comes back on your inbound webhook, so use stable, meaningful ids (confirm_yes, not btn1). Keep title short — WhatsApp truncates long labels.

Interactive: List Menus

A list menu shows a single button that opens a scrollable menu grouped into sections. It's the right choice when you have more options than three buttons allow — for example choosing a department or picking a product. A list supports up to 10 rows in total across its sections.

Set interactive.type to "list". The action.button is the label on the opener; action.sections groups the rows, each with an id (returned on selection), a title, and an optional description.

NODE.JS — DEPARTMENT PICKER
const response = await fetch('https://cliqtel.com/api/v1/whatsapp/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    account_id: 1,
    to: '+31611398058',
    type: 'interactive',
    interactive: {
      type: 'list',
      header: { type: 'text', text: 'How can we help?' },
      body: { text: 'Choose the team you would like to reach.' },
      footer: { text: 'Cliqtel' },
      action: {
        button: 'Choose a department',
        sections: [
          {
            title: 'Support',
            rows: [
              { id: 'dept_sales',    title: 'Sales',    description: 'Pricing and new orders' },
              { id: 'dept_billing',  title: 'Billing',  description: 'Invoices and payments' },
              { id: 'dept_tech',     title: 'Technical', description: 'Setup and troubleshooting' },
            ],
          },
        ],
      },
    },
  }),
});

const data = await response.json();
console.log(data.id, data.status);
PYTHON
import requests

resp = requests.post(
    'https://cliqtel.com/api/v1/whatsapp/messages',
    headers={'Authorization': 'Bearer YOUR_API_KEY'},
    json={
        'account_id': 1,
        'to': '+31611398058',
        'type': 'interactive',
        'interactive': {
            'type': 'list',
            'header': {'type': 'text', 'text': 'How can we help?'},
            'body': {'text': 'Choose the team you would like to reach.'},
            'footer': {'text': 'Cliqtel'},
            'action': {
                'button': 'Choose a department',
                'sections': [
                    {
                        'title': 'Support',
                        'rows': [
                            {'id': 'dept_sales',   'title': 'Sales',     'description': 'Pricing and new orders'},
                            {'id': 'dept_billing', 'title': 'Billing',   'description': 'Invoices and payments'},
                            {'id': 'dept_tech',    'title': 'Technical', 'description': 'Setup and troubleshooting'},
                        ],
                    },
                ],
            },
        },
    },
)

print(resp.json()['id'], resp.json()['status'])
Building menus without code? The WhatsApp Flow Builder lets you assemble button and list menus visually and wire up what each choice does, no API calls required.

Delivery Status

Add an optional status_callback_url to any send to receive delivery status webhooks as the message progresses. Cliqtel posts updates for sent, delivered, read and failed, each carrying the Cliqtel message id so you can correlate it with the send.

NODE.JS — SEND WITH A STATUS CALLBACK
await fetch('https://cliqtel.com/api/v1/whatsapp/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    account_id: 1,
    to: '+31611398058',
    type: 'text',
    body: 'Thanks — your order is on its way!',
    status_callback_url: 'https://example.com/webhooks/whatsapp-status',
  }),
});
Tip: A failed status is your cue to fall back — for example retry via a template if the 24-hour window has closed, or via SMS for a contact without WhatsApp.

Best Practices

  • Respect the window — use a template to open a conversation, then rich free-form types once the customer replies.
  • Upload media once, reuse the id — don't re-upload the same brochure for every send.
  • Give buttons and rows stable, meaningful ids (dept_billing) so your inbound handler stays readable.
  • Keep button titles and row titles short — WhatsApp truncates long labels.
  • Prefer reply buttons for up to three choices; switch to a list menu when you need more (up to 10 rows).
  • Always set a status_callback_url in production so you can detect and recover from failures.
  • Stay under the 60 requests/minute rate limit — batch or queue high-volume sends.

FAQ

Why was my text or media message rejected?

The most common reason is a closed 24-hour window. Free-form messages (text, media, location, interactive) only deliver within 24 hours of the customer's last inbound message. If the window has closed, send a pre-approved template first; once the customer replies you'll have a fresh window.

How do I get a media id?

Upload the file through the Cliqtel portal or the media API, which returns a media id. Reference that id in media.id. Where supported you can also send media by link instead of uploading first.

How many buttons or list rows can I use?

Reply buttons support up to 3 buttons. List menus support up to 10 rows in total across all their sections. If you need more options than three buttons allow, use a list menu.

How do I know which button or row the customer tapped?

Their selection arrives as an inbound message carrying the id you set on that button or row. Use descriptive ids so your handler can route the reply without a lookup table.

How do I track whether a message was delivered?

Include a status_callback_url on the send. Cliqtel posts delivery status webhooks — sent, delivered, read and failed — each referencing the Cliqtel message id from the send response.

Where's the full API reference?

See the full API reference for every field and endpoint, and the WhatsApp setup guide for connecting your account.

Ready to send rich WhatsApp messages?

Connect your WhatsApp account, then explore the full messaging API reference.

API Reference →
© 2026 Cliqtel · cliqtel.com
会社情報 ブログ パートナー 対応エリア APIドキュメント ステータス プライバシー 利用規約 Cookie ヘルプ 検索
cliqtel.comはオランダ・ザイストに登記されたCliqtel B.V.が運営しています · KVK 42033793 · VAT NL869402468B01 · SBI 62.09

Cliqtelの動作に必要な必須Cookieを使用しています。お客様の同意のもと、サービス改善のために分析Cookieも使用します。Cookieポリシー