Skip to content

Send Template Message

Send a pre-approved WhatsApp message template. Templates can be sent outside the 24-hour messaging window.

POST /api/v1/messages/send

Request

Headers

HeaderRequiredDescription
AuthorizationYesBearer YOUR_API_KEY
Content-TypeYesapplication/json
X-TENANT-IDNoTenant ID (if multi-tenant)

Body Parameters

ParameterTypeRequiredDescription
whatsapp_account_idstringYesWhatsApp account ID to send from — Dashboard → WhatsApp Numbers → API ID:
phonestringYesRecipient phone number with country code
message_typestringYesMust be template
dataobjectYesTemplate data object
data.namestringYesTemplate name (e.g., order_confirmation)
data.language_codestringNoTemplate language code (default: en_US)
data.componentsarrayNoMeta components array with template parameters. Required when the template has an image/video/document header — pass a header component with the media link or id, otherwise the API returns TEMPLATE_HEADER_MEDIA_REQUIRED (422).
scheduled_atstringNoISO 8601 datetime for delayed send
timezonestringNoIANA timezone (required when scheduled_at is set)
auto_retry_on_frequency_capbooleanNoOpt-in 26-hour auto-retry when Meta rejects the message with error 131049 (per-recipient marketing frequency cap). The platform automatically creates a single scheduled retry — never more, to prevent loops. Recommended true for marketing templates, false for transactional ones. Default: false.

Header media on send

If the template was created with an image, video, or document header, every send MUST include a header component carrying the actual media for that recipient. You can:

  • Reuse the template's default sample: fetch the template via GET /api/v1/templates and read header_sample_media_url, then pass it as the link below.
  • Send recipient-specific media: upload it to public storage and pass that URL — or use a previously-uploaded Meta media id.
json
"components": [
  {
    "type": "header",
    "parameters": [
      { "type": "image", "image": { "link": "https://example.com/banner.jpg" } }
    ]
  },
  { "type": "body", "parameters": [ {"type": "text", "text": "ORD-1234"} ] }
]

Frequency-cap auto-retry (131049)

Meta enforces a per-recipient cap on marketing messages: a user can only receive a small number of marketing-category messages from businesses in any 24-hour window. When the cap is hit, Meta rejects further sends with error 131049not a technical bug, a policy. The retry option converts this silent failure into a deferred delivery:

  • On 131049 failure with auto_retry_on_frequency_cap: true, the platform creates a scheduled message at now + 26 hours (24h Meta window + 2h safety margin) carrying the same recipient + template + params.
  • That retry runs through the normal scheduled-message cron; you can find it in the dashboard's Sent page with retry_count = 1.
  • The retry itself runs with auto_retry_on_frequency_cap = false and retry_count = 1a single retry per chain, no loops even if Meta rejects it again.

Example Request

bash
curl -X POST https://cubeconnect.io/api/v1/messages/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "whatsapp_account_id": "YOUR_WHATSAPP_ACCOUNT_ID",
    "phone": "+966501234567",
    "message_type": "template",
    "data": {
      "name": "order_confirmation",
      "language_code": "en_US",
      "components": [
        {
          "type": "body",
          "parameters": [
            {"type": "text", "text": "ORD-1234"},
            {"type": "text", "text": "500 SAR"}
          ]
        }
      ]
    }
  }'
php
$response = Http::withToken('YOUR_API_KEY')
    ->post('https://cubeconnect.io/api/v1/messages/send', [
        'whatsapp_account_id' => env('CUBECONNECT_WHATSAPP_ACCOUNT_ID'),
        'phone'        => '+966501234567',
        'message_type' => 'template',
        'data'         => [
            'name'          => 'order_confirmation',
            'language_code' => 'en_US',
            'components'    => [
                [
                    'type'       => 'body',
                    'parameters' => [
                        ['type' => 'text', 'text' => 'ORD-1234'],
                        ['type' => 'text', 'text' => '500 SAR'],
                    ],
                ],
            ],
        ],
    ]);
javascript
const response = await fetch('https://cubeconnect.io/api/v1/messages/send', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    whatsapp_account_id: process.env.CUBECONNECT_WHATSAPP_ACCOUNT_ID,
    phone: '+966501234567',
    message_type: 'template',
    data: {
      name: 'order_confirmation',
      language_code: 'en_US',
      components: [
        {
          type: 'body',
          parameters: [
            { type: 'text', text: 'ORD-1234' },
            { type: 'text', text: '500 SAR' },
          ],
        },
      ],
    },
  }),
})
python
import requests

response = requests.post(
    'https://cubeconnect.io/api/v1/messages/send',
    headers={
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json',
    },
    json={
        'whatsapp_account_id': 'YOUR_WHATSAPP_ACCOUNT_ID',
        'phone': '+966501234567',
        'message_type': 'template',
        'data': {
            'name': 'order_confirmation',
            'language_code': 'en_US',
            'components': [
                {
                    'type': 'body',
                    'parameters': [
                        {'type': 'text', 'text': 'ORD-1234'},
                        {'type': 'text', 'text': '500 SAR'},
                    ],
                },
            ],
        },
    },
)

Response

Success 202 Accepted

json
{
  "success": true,
  "data": {
    "status": "queued",
    "message_log_id": 4522,
    "conversation_category": "MARKETING",
    "cost": 0.0
  }
}

The conversation_category is determined automatically based on the template's category in Meta Business Manager.

Template Parameters

Templates use positional placeholders like 1, 2, etc. The components array follows the Meta WhatsApp API format.

Example Template

Template name: order_confirmationTemplate body:

Your order {{1}} has been confirmed.
Total amount: {{2}}.
Thank you for your purchase!

API call components:

json
{
  "components": [
    {
      "type": "body",
      "parameters": [
        {"type": "text", "text": "ORD-1234"},
        {"type": "text", "text": "500 SAR"}
      ]
    }
  ]
}

Result sent to customer:

Your order ORD-1234 has been confirmed.
Total amount: 500 SAR.
Thank you for your purchase!

Template Categories

CategoryDescriptionWhen to Use
MARKETINGPromotional contentSales, offers, product announcements
UTILITYTransactional updatesOrder confirmations, shipping updates, account alerts
AUTHENTICATIONOTP and verificationLogin codes, 2FA, verification

Template Without Parameters

If the template has no dynamic parameters, omit the components field:

json
{
  "phone": "+966501234567",
  "message_type": "template",
  "data": {
    "name": "welcome_message",
    "language_code": "en_US"
  }
}

Common Errors

ErrorCause
Template not foundThe template name doesn't exist or hasn't been approved
Parameter count mismatchThe number of parameters in components doesn't match the template's placeholders
Template pausedMeta has paused the template due to quality issues

Template Approval

Templates must be approved by Meta before they can be sent. Create and manage templates from the CubeConnect dashboard under Templates.

CubeConnect WhatsApp Business Platform