The Messaging API groups the endpoints that send WhatsApp messages, trigger automations, rename your contacts and read your account information. It requires an active subscription: without one, every call returns 403 Team has no active subscription.
These endpoints do not take a store_id: your API key is attached to a WhatsApp number, which is the sending number. See API authentication and keys.
WhatsApp only allows free-form messages within an open 24-hour service window, that is, when the contact has written to you in the last 24 hours. To contact someone first, you must use an approved template.
POST /api/v1/messages/sendThe format follows Meta's logic: a type field, then an object named after that type.
to (required): the recipient's number, including the country code.
type (required): text, image, video, audio or document.
text.body: required for the text type.
<type>.link: required for all other types (media URL).
<type>.caption (optional): caption, accepted for images, videos and documents.
document.filename (optional): file name shown to the recipient.
curl -X POST https://api.getkanal.com/api/v1/messages/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "33612345678",
"type": "text",
"text": { "body": "Hello from the API!" }
}'For an image:
{
"to": "33612345678",
"type": "image",
"image": {
"link": "https://example.com/photo.jpg",
"caption": "Optional caption"
}
}For a document:
{
"to": "33612345678",
"type": "document",
"document": {
"link": "https://example.com/invoice.pdf",
"caption": "Your invoice",
"filename": "invoice-10456.pdf"
}
}The most common error on this endpoint is Cannot send free-form message: no active conversation window. It means the 24-hour window is closed: use a template. The other cases are an invalid number, an opted-out contact, or a badly filled message type.
POST /api/v1/templatesThis is the only way to contact a customer first. Parameters and the variables format are detailed in Send a WhatsApp template via the API.
GET /api/v1/get_templatesReturns an array of your templates with the APPROVED status for the number attached to the key, including those created in an automation or a campaign. No parameters: only the Authorization header is needed.
[
{
"id": 1234,
"phone_number_id": 56,
"name": "order_confirmation",
"wa_status": "APPROVED",
"structure": "{ ...JSON: header/body/buttons... }",
"created_at": "2026-01-10T12:00:00.000000Z"
}
]The id field is the template_id to use when sending. The structure field is a JSON string describing the header, body and buttons: the variable names it contains are exactly the keys to pass in the variables object when sending.
POST /api/v1/automations/{webhook_id}Starts an automation whose trigger is an Incoming Webhook. The webhook_id is the UUID of this node. In the automation editor, the Incoming Webhook node shows the full Destination URL and a button to copy the call as cURL. The automation must be active and belong to the key's WhatsApp number.
Fields accepted at the root of the JSON:
phone_number (required): the contact's number. If no contact exists for this number, it is created.
variables (optional): a key/value object injected into the automation's session variables.
name, first_name, last_name (optional): the contact's identity.
email (optional): added only if the contact does not have an email yet.
shopify_customer_id (optional): must be numeric, links the contact to a Shopify customer.
curl -X POST https://api.getkanal.com/api/v1/automations/3f9c1a2b-4d5e-6789-abcd-ef0123456789 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+33612345678",
"first_name": "Marie",
"email": "[email protected]",
"variables": { "discount_code": "WELCOME10" }
}'Code | Message | Meaning |
|---|---|---|
|
| The flow has started. |
|
| The automation's re-entry rule blocks this contact: no flow starts. |
|
| The automation is turned off: activate it. |
|
| Missing or invalid number. |
|
| The Shopify customer ID is not numeric. |
|
| The automation belongs to a different WhatsApp number than the key's. |
|
| The |
200 response does not guarantee that the flow started: check the message field. This endpoint uses a { "message": ... } format, not { "error": ... }.Older URLs of the form https://api.getkanal.com/v1/automations/{webhook_id} (without /api) are still accepted for existing integrations. Use /api/v1/ for any new integration.
PATCH /api/v1/contacts/{phone}Available since October 8, 2026. This endpoint changes the name of an existing contact of your number. It never creates a contact: an unknown number returns 404 Contact not found.
{phone}: the contact's number, including the country code, with or without + (for example 33612345678).
name: the name shown in the Inbox. It does not change first_name or last_name.
first_name: the first name, used by personalization variables in templates and automations.
last_name: the last name.
Send at least one of these three fields, otherwise the API returns a 422 error. Only the fields you send are changed.
curl -X PATCH https://api.getkanal.com/api/v1/contacts/33612345678 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "140 - John Smith" }'POST /api/v1/meReturns the WhatsApp Business number attached to the key. No request body. It is the fastest call to check that a key works and confirm which number it sends from.
{
"display_phone_number": "+33 6 12 34 56 78",
"verified_name": "My Shop"
}The /messages/send and /templates endpoints accept an optional Idempotency-Key header. Replaying a request with the same key does not send the message again: the API returns a 201 stating that the message was already sent. Use a unique value, for example one UUID per message: a key already known to Kanal is treated as a duplicate.
Only POST /api/v1/templates is limited to 60 requests per minute per API key. Beyond that, the API returns a 429 error with retry_after: 60. The other Messaging API endpoints are only subject to the global API limit: 3,000 requests per minute per IP address.