oToK Developer Docs

Templates (WhatsApp)

Read your workspace's WhatsApp message templates and send a template message to a phone number. Template creation, editing, and deletion are managed in the oToK app — the API surface is deliberately read-and-send only.

All endpoints require authentication. Standard list conventions apply to the list route.

Method Path Purpose
GET /api/v1/templates List templates
GET /api/v1/templates/:id Get one template
POST /api/v1/templates/:id/send Send a template message

The template object

Template rows include: id, name, display_name, category, language, status, header_type, header_text, body_text, body_variables_examples, footer_text, buttons, meta_template_id, rejection_reason, created_at, updated_at. Only templates with an approved status can be delivered by WhatsApp.

GET /api/v1/templates

curl -G "https://app.otok.io/api/v1/templates" \
  -H "Authorization: Bearer otok_live_abc123..." \
  --data-urlencode 'filter={"status":"approved"}'

Response 200{ data, total, limit, offset } with full template rows.

Status Meaning
400 Invalid filter / limit / offset / a mistyped filter value (Invalid filter value for "<field>": … — see filter-value validation)

GET /api/v1/templates/:id

Response 200 — a full template row. 404"messageTemplates with ID <id> not found". Non-UUID id → 400.

POST /api/v1/templates/:id/send

Sends the template to a phone number. The template must belong to your workspace (404 otherwise). The recipient contact is matched by normalized phone — created automatically if it doesn't exist — and the sent message is recorded in the Inbox conversation.

Request body

Field Type Required Constraints
to string yes Recipient phone, international format (e.g. +972501234567)
body_variables array no Values for the template's body placeholders. Item shape: { "type": string, "text": string, "param_name"?: string }type and text are required. param_name matches named placeholders; otherwise values apply by position
header_config object no { "type": "text", "variables"?: ["..."] } for text headers, or `{ "type": "media", "media_type": "image"
button_configs array no Values for dynamic buttons (e.g. dynamic-URL suffixes). Item shape: { "type": string, "index": integer ≥ 0, "parameters": string[] }parameters is required; send [] for a button with no dynamic values

The nested shapes of body_variables / header_config / button_configs are strictly validated on the request: a malformed entry (e.g. body_variables: [null], or a button without parameters) returns 400 Bad Request in the standard validation shape, where message is an array of per-field strings — e.g. ["body_variables.0.text must be a string"]. Unknown properties inside these nested objects are rejected too (property <name> should not exist), consistent with top-level body validation. Content that only the WhatsApp provider rejects still surfaces as a 502.

Example

curl -X POST "https://app.otok.io/api/v1/templates/1f2e3d4c-5b6a-7980-a1b2-c3d4e5f60718/send" \
  -H "Authorization: Bearer otok_live_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+972501234567",
    "body_variables": [
      { "type": "text", "text": "Dana", "param_name": "name" },
      { "type": "text", "text": "July 20" }
    ],
    "header_config": { "type": "media", "media_type": "image", "media_link": "https://example.com/banner.jpg" }
  }'

Response 201:

{
  "success": true,
  "wamid": "wamid.HBgLOTcyNTAxMjM0NTY3FQIAERgSNzdBRjA1RkYxMkI0QzhGOUEA",
  "message_id": "8a7b6c5d-4e3f-2a1b-0c9d-8e7f6a5b4c3d",
  "conversation_id": "0d9c8b7a-6f5e-4d3c-2b1a-09f8e7d6c5b4"
}

Errors

Status Message Meaning
400 ["body_variables.0.text must be a string"] (array of per-field messages) Malformed nested body_variables / header_config / button_configs entries, or unknown nested properties
400 "Cannot send WhatsApp template — missing required field(s): …" The template requires variables/config you didn't supply
400 Invalid header media_type "<x>". Must be one of: image, video, document Bad header_config.media_type
403 "This contact is blocked" The resolved contact is blocked in this workspace
403 "This phone number is on the blacklist and cannot be messaged" Blacklist rule matches the recipient number
404 "messageTemplates with ID <id> not found" Template not in this workspace
404 "No connected WhatsApp instance found" No active WhatsApp connection to send from
502 { "message": "<provider error>", "message_id": "...", "conversation_id": "..." } WhatsApp/Meta refused the send. The failed message row is persistedmessage_id/conversation_id are included so you can retry or inspect it in the Inbox

Side effects

A successful send writes the message and conversation to the Inbox (status progresses pending → sent → delivered/read via WhatsApp receipts), counts toward the workspace's monthly message usage, and — when workspace link tracking is enabled — decorates links in the message with tracking parameters.