{"openapi":"3.1.0","info":{"title":"Platform API","version":"1.0.0","description":"Send WhatsApp messages, receive customer replies and delivery updates, and connect the platform to your own systems."},"servers":[{"url":"https://api.saei.automize.sa/v1"}],"security":[{"apiKey":[]}],"tags":[{"name":"Account","description":"Check your key and what it can do.","x-display-name":{"en":"Account","ar":"الحساب"}},{"name":"Messages","description":"Send messages and read their status.","x-display-name":{"en":"Messages","ar":"الرسائل"}},{"name":"Numbers","description":"Your WhatsApp sending numbers and their health.","x-display-name":{"en":"Numbers","ar":"الأرقام"}},{"name":"Templates","description":"Approved WhatsApp templates: read what each needs, create new ones.","x-display-name":{"en":"Templates","ar":"القوالب"}},{"name":"Media","description":"Upload files once and send them as often as you like.","x-display-name":{"en":"Media","ar":"الوسائط"}},{"name":"Contacts","description":"Keep contacts, tags and custom fields in step with your systems.","x-display-name":{"en":"Contacts","ar":"جهات الاتصال"}},{"name":"Conversations","description":"The shared inbox: read threads, assign, resolve and reopen.","x-display-name":{"en":"Conversations","ar":"المحادثات"}},{"name":"Campaigns","description":"Broadcast an approved template to an audience, and follow the results.","x-display-name":{"en":"Campaigns","ar":"الحملات"}},{"name":"Flows","description":"Start your flow-builder automations for a customer.","x-display-name":{"en":"Flows","ar":"التدفقات"}},{"name":"Usage","description":"What the workspace used this period, against its plan.","x-display-name":{"en":"Usage","ar":"الاستهلاك"}},{"name":"Webhooks","description":"Get events (new messages, delivery updates) pushed to your server.","x-display-name":{"en":"Webhooks","ar":"الويب هوك"}},{"name":"Test mode","description":"Drive the test-mode simulator on purpose. Test keys only.","x-display-name":{"en":"Test mode","ar":"وضع الاختبار"}}],"paths":{"/campaigns":{"get":{"operationId":"listCampaigns","tags":["Campaigns"],"summary":"List campaigns","x-required-scopes":["campaigns:read"],"x-test-mode":"unsupported","x-errors":["parameter_invalid","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","scheduled","in_progress","paused","completed","failed","cancelled"]}}],"responses":{"200":{"description":"A page of campaigns.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createCampaign","tags":["Campaigns"],"summary":"Create a campaign","description":"Creates a **draft**: nothing is sent until you call `POST /v1/campaigns/{id}/start`. The answer carries `estimated_cost`, the price WhatsApp will charge at today's rates, so you can confirm before sending.\n\n- **Audience**: `contacts` (ids), `tags` (ids or names), or `all_contacts: true`.\n- **Variables**: the template's values, where `{{first_name}}`, `{{last_name}}`, `{{phone_number}}` or any custom field key is filled in per recipient, e.g. `\"body\": [\"{{first_name}}\", \"20%\"]`.\n- **Consent**: if some recipients opted out of business messages, the answer is `recipient_not_consented` with the counts. Send `consent_confirmed: false` to skip them, or `true` only if they agreed again (your confirmation is recorded in the audit log).\n\nEvery check the campaign builder makes applies here too: a number Meta has limited cannot broadcast, the template must belong to the sending number, and the plan's monthly campaign and marketing-message allowances are enforced at start.\n","x-required-scopes":["campaigns:write"],"x-test-mode":"unsupported","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","resource_missing","template_not_found","template_not_approved","template_variables_mismatch","recipient_not_consented","sender_not_sendable","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignInput"},"example":{"name":"عرض نهاية الأسبوع","template":{"name":"weekend_offer","language":"ar"},"number_id":"num_3","audience":{"tags":["عملاء VIP"]},"variables":{"body":["20٪"]},"scheduled_at":"2026-10-02T16:00:00","timezone":"Asia/Riyadh"}}}},"responses":{"201":{"description":"The draft, with its price estimate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"},"example":{"id":"cmp_64","object":"campaign","name":"عرض نهاية الأسبوع","description":null,"status":"draft","hold_reason":null,"template":{"id":"tpl_31","name":"weekend_offer","language":"ar"},"number_id":"num_3","scheduled_at":"2026-10-02T13:00:00Z","timezone":"Asia/Riyadh","stats":{"recipients":348,"sent":0,"delivered":0,"read":0,"failed":0},"estimated_cost":{"currency":"SAR","total":61.25,"total_usd":16.33,"recipients_priced":348,"recipients_free":0,"recipients_unpriced":0},"created_at":"2026-10-01T10:00:00Z","updated_at":"2026-10-01T10:00:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Some recipients have not consented; answer with `consent_confirmed`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/campaigns/{id}":{"get":{"operationId":"getCampaign","tags":["Campaigns"],"summary":"Get a campaign","description":"The campaign with live results (sent, delivered, read, failed, replied and the rates).","x-required-scopes":["campaigns:read"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The campaign.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/campaigns/{id}/cancel":{"post":{"operationId":"cancelCampaign","tags":["Campaigns"],"summary":"Cancel a campaign","description":"Stops a scheduled or sending campaign. Messages already sent stay sent; the rest are cancelled.","x-required-scopes":["campaigns:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","state_conflict","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Not scheduled or sending.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/campaigns/{id}/messages":{"get":{"operationId":"listCampaignMessages","tags":["Campaigns"],"summary":"List a campaign's recipients","description":"One `message` per recipient (`cmsg_…`), with its delivery status and, for a failure, WhatsApp's reason. Their status changes also arrive as `message.*` events.","x-required-scopes":["campaigns:read"],"x-test-mode":"unsupported","x-errors":["resource_missing","parameter_invalid","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","sent","delivered","read","failed","cancelled"]}}],"responses":{"200":{"description":"A page of recipient messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/campaigns/{id}/resume":{"post":{"operationId":"resumeCampaign","tags":["Campaigns"],"summary":"Resume a paused campaign","description":"Puts a held campaign back on the queue once its cause is fixed. Only ever by an explicit call, never by itself (except after a platform-wide pause), because a number just back from a restriction should not start broadcasting unattended. Refused while the number still cannot broadcast.","x-required-scopes":["campaigns:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","state_conflict","sender_not_sendable","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Sending again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Not paused.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/campaigns/{id}/start":{"post":{"operationId":"startCampaign","tags":["Campaigns"],"summary":"Start a campaign","description":"Sends the draft now, or at its `scheduled_at`. Sending is paced to protect the number's quality rating; follow progress with `campaign.*` events and `GET /v1/campaigns/{id}`.","x-required-scopes":["campaigns:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","state_conflict","sender_not_sendable","sender_not_configured","quota_exceeded","channel_error","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Started (`in_progress`) or scheduled (`scheduled`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"The plan's monthly campaigns or marketing messages are used up.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Already started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/contact_fields":{"get":{"operationId":"listContactFields","tags":["Contacts"],"summary":"List custom contact fields","description":"The custom fields your contacts carry (created in Contacts → Fields). Use each `key` in a contact's `fields`.","x-required-scopes":["contacts:read"],"x-test-mode":"supported","x-errors":["rate_limited"],"responses":{"200":{"description":"Every custom field, in the portal's order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactFieldList"},"example":{"object":"list","data":[{"id":"fld_4","object":"contact_field","key":"city_branch","label":"الفرع","type":"select","options":["الرياض","جدة"],"required":false},{"id":"fld_5","object":"contact_field","key":"loyalty_points","label":"نقاط الولاء","type":"number","options":null,"required":false}],"has_more":false,"next_cursor":null}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/contacts":{"get":{"operationId":"listContacts","tags":["Contacts"],"summary":"List contacts","description":"Your WhatsApp contacts, newest first. Find one person with `phone` (any format: `+966 50 123 4567`, `0501234567`…), or sync changes with `updated_since`.","x-required-scopes":["contacts:read"],"x-test-mode":"unsupported","x-errors":["parameter_invalid","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"phone","in":"query","schema":{"type":"string"}},{"name":"email","in":"query","schema":{"type":"string"}},{"name":"tag","in":"query","description":"A tag id (`tag_…`) or name.","schema":{"type":"string"}},{"name":"opted_in","in":"query","schema":{"type":"boolean"}},{"name":"updated_since","in":"query","description":"Only contacts changed at or after this time (ISO 8601).","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"A page of contacts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createContact","tags":["Contacts"],"summary":"Create a contact","description":"One phone number is one contact: if the number already exists the answer is `resource_exists` with the `existing_id`. To create-or-update in one call, use `POST /v1/contacts/upsert`.\n\n`tags` takes tag ids or names; a name that does not exist yet is created. `fields` takes custom field values by `key` (see `GET /v1/contact_fields`).\n","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","resource_exists","resource_missing","quota_exceeded","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInput"},"example":{"phone":"+966501234567","first_name":"سارة","last_name":"القحطاني","email":"sara@example.com","language":"ar","tags":["عملاء VIP"],"fields":{"loyalty_points":120},"consent":{"source":"website_form"}}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"},"example":{"id":"ct_1052","object":"contact","phone":"+966501234567","email":"sara@example.com","first_name":"سارة","last_name":"القحطاني","language":"ar","country":null,"city":null,"gender":null,"birth_date":null,"notes":null,"opted_in":true,"consent":{"source":"website_form","captured_at":"2026-10-01T10:02:00Z"},"opted_out_at":null,"bot_enabled":true,"tags":[{"id":"tag_12","name":"عملاء VIP"}],"fields":{"loyalty_points":"120"},"created_at":"2026-10-01T10:02:00Z","updated_at":"2026-10-01T10:02:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"The plan's contact limit is reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A contact with this phone or email exists; `existing_id` names it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/contacts/upsert":{"post":{"operationId":"upsertContact","tags":["Contacts"],"summary":"Create or update a contact by phone","description":"The call to keep your CRM and this workspace in step. Finds the contact by `phone` (in any format) and updates the fields you send, or creates it. `201` when created, `200` when updated.","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","resource_exists","resource_missing","quota_exceeded","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactInput"},"example":{"phone":"0501234567","first_name":"سارة","fields":{"loyalty_points":180}}}}},"responses":{"200":{"description":"Updated an existing contact.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"201":{"description":"Created a new contact.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Invalid"}}}},"/contacts/{id}":{"get":{"operationId":"getContact","tags":["Contacts"],"summary":"Get a contact","x-required-scopes":["contacts:read"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The contact.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateContact","tags":["Contacts"],"summary":"Update a contact","description":"Changes only the fields you send. `tags` replaces the tag list (to add one, use `POST /v1/contacts/{id}/tags`); `fields` changes only the keys you send, and an empty value clears one.\n\n`opted_in: false` opts the contact out the way a STOP message does: queued campaign messages to them are cancelled. `opted_in: true` needs `consent` saying how they agreed.\n","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-errors":["parameter_missing","parameter_invalid","resource_missing","resource_exists","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpdate"},"examples":{"details":{"summary":"Change details","value":{"city":"جدة","fields":{"loyalty_points":200}}},"opt_out":{"summary":"Opt out","value":{"opted_in":false}},"opt_in":{"summary":"Opt back in","value":{"opted_in":true,"consent":{"source":"paper_form"}}}}}}},"responses":{"200":{"description":"The updated contact.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}},"delete":{"operationId":"deleteContact","tags":["Contacts"],"summary":"Delete a contact","description":"Deletes the contact, its tags and custom field values. Campaign messages still queued for them are cancelled. The conversation history stays in the inbox.","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"},"example":{"id":"ct_1052","object":"contact","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/contacts/{id}/tags":{"post":{"operationId":"addContactTags","tags":["Contacts"],"summary":"Add tags to a contact","description":"Adds the tags (ids or names; a new name creates the tag) and keeps the ones the contact already has.","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-errors":["parameter_missing","resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"}}}},"example":{"tags":["tag_12","اشترى مؤخرًا"]}}}},"responses":{"200":{"description":"The contact with its tags.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}}},"/contacts/{id}/tags/{tag}":{"delete":{"operationId":"removeContactTag","tags":["Contacts"],"summary":"Remove a tag from a contact","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"},{"name":"tag","in":"path","required":true,"description":"The tag id (`tag_…`) or its name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The contact without the tag.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Contact"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/conversations":{"get":{"operationId":"listConversations","tags":["Conversations"],"summary":"List conversations","description":"Threads in the shared inbox, newest first, on WhatsApp, Instagram and Messenger. Filter to build your own queue: `open=true&assignee=none` is everything waiting for someone.","x-required-scopes":["conversations:read"],"x-test-mode":"unsupported","x-errors":["parameter_invalid","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"open","in":"query","description":"`true` for unresolved conversations, `false` for resolved ones.","schema":{"type":"boolean"}},{"name":"state","in":"query","schema":{"type":"string","enum":["bot","needs_agent","assigned","human","resolved","snoozed"]}},{"name":"channel","in":"query","schema":{"type":"string","enum":["whatsapp","instagram","messenger"]}},{"name":"assignee","in":"query","description":"A member id (`usr_…`), or `none` for unassigned.","schema":{"type":"string"}},{"name":"customer","in":"query","description":"The customer's phone (any format) or Instagram / Messenger id.","schema":{"type":"string"}},{"name":"unread","in":"query","schema":{"type":"boolean"}}],"responses":{"200":{"description":"A page of conversations.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/conversations/{id}":{"get":{"operationId":"getConversation","tags":["Conversations"],"summary":"Get a conversation","x-required-scopes":["conversations:read"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"},"example":{"id":"conv_311","object":"conversation","channel":"whatsapp","customer":{"contact_id":"ct_1052","address":"+966501234567","name":"سارة القحطاني"},"number_id":"num_3","state":"assigned","open":true,"assignee":{"id":"usr_41","name":"نورة العتيبي"},"unread":true,"label":"شكوى","last_customer_message_at":"2026-10-01T09:29:10Z","last_agent_message_at":"2026-10-01T09:20:00Z","reply_window_expires_at":"2026-10-02T09:29:10Z","resolved_at":null,"snoozed_until":null,"created_at":"2026-09-28T14:00:00Z","updated_at":"2026-10-01T09:29:10Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/conversations/{id}/assign":{"post":{"operationId":"assignConversation","tags":["Conversations"],"summary":"Assign a conversation","description":"Hands the conversation to a team member. They must be able to see its number or account; viewers cannot be assigned.","x-required-scopes":["conversations:write"],"x-test-mode":"unsupported","x-errors":["parameter_missing","resource_missing","assignee_invalid","state_conflict","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["member_id"],"properties":{"member_id":{"type":"string","description":"From `GET /v1/members`."}}},"example":{"member_id":"usr_41"}}}},"responses":{"200":{"description":"The conversation, now assigned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Resolved conversations must be reopened first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/conversations/{id}/messages":{"get":{"operationId":"listConversationMessages","tags":["Conversations"],"summary":"List a conversation's messages","description":"Every message in the thread, both directions, newest first. Internal notes between agents are never included.","x-required-scopes":["conversations:read"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/conversations/{id}/reopen":{"post":{"operationId":"reopenConversation","tags":["Conversations"],"summary":"Reopen a conversation","description":"Reopens a resolved conversation, unassigned in the team queue, or assigned to `member_id`.","x-required-scopes":["conversations:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","state_conflict","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"member_id":{"type":["string","null"]}}},"example":{"member_id":"usr_41"}}}},"responses":{"200":{"description":"The reopened conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Not resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/conversations/{id}/resolve":{"post":{"operationId":"resolveConversation","tags":["Conversations"],"summary":"Resolve a conversation","description":"Closes the conversation. If the customer writes again it reopens by itself, and you get `conversation.reopened`.","x-required-scopes":["conversations:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","state_conflict","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The resolved conversation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Already resolved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/event_types":{"get":{"operationId":"listEventTypes","tags":["Webhooks"],"summary":"List event types","description":"Every event you can subscribe an endpoint to.","x-required-scopes":["webhooks:read"],"x-test-mode":"supported","x-errors":[],"responses":{"200":{"description":"The event types.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventTypeList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/flow_responses":{"get":{"operationId":"listFlowResponses","tags":["Flows"],"summary":"List WhatsApp Flow form responses","description":"Answers customers submitted in WhatsApp Flows (the forms that open inside the chat), newest first. Each new one also arrives as a `flow.response` event.","x-required-scopes":["flows:read"],"x-test-mode":"unsupported","x-errors":["parameter_invalid","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"whatsapp_flow_id","in":"query","description":"Only responses to this WhatsApp Flow (Meta's flow id).","schema":{"type":"string"}},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"A page of responses.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowResponseList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/flow_runs/{id}":{"get":{"operationId":"getFlowRun","tags":["Flows"],"summary":"Get a flow run","description":"Where one customer is in a flow, and the variables the flow has collected so far (answers, choices, values from your systems).","x-required-scopes":["flows:read"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The run.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRun"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/flows":{"get":{"operationId":"listFlows","tags":["Flows"],"summary":"List flows","description":"The automation flows built in the flow builder. `startable_via_api` marks the published flows with an \"API / webhook\" trigger, which `POST /v1/flows/{id}/runs` can start for a customer.","x-required-scopes":["flows:read"],"x-test-mode":"supported","x-errors":["parameter_invalid","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","published","archived"]}},{"name":"startable_via_api","in":"query","description":"`true` for only the flows you can start through the API.","schema":{"type":"boolean"}}],"responses":{"200":{"description":"A page of flows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/flows/{id}":{"get":{"operationId":"getFlow","tags":["Flows"],"summary":"Get a flow","x-required-scopes":["flows:read"],"x-test-mode":"supported","x-errors":["resource_missing","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The flow.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Flow"},"example":{"id":"flow_18","object":"flow","name":"متابعة بعد الشراء","description":"يسأل العميل عن تجربته بعد 3 أيام من التسليم","status":"published","trigger":"webhook","startable_via_api":true,"number_id":"num_3","published_at":"2026-09-01T08:00:00Z","created_at":"2026-08-28T12:00:00Z","updated_at":"2026-09-01T08:00:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/flows/{id}/runs":{"post":{"operationId":"startFlowRun","tags":["Flows"],"summary":"Start a flow for a customer","description":"Runs the flow for one customer now, exactly as its \"API / webhook\" trigger would: the same steps, messages, waits and hand-offs. `variables` become the run's starting variables (the flow reads them as `{{name}}`), next to what it already knows about the contact. The customer comes from `to` only: `contact_id`, `contact_phone`, `phone`, `phone_number`, `customer` and keys starting with `_` are reserved and refused. `reference` is your own id, returned on the run and in every `flow.run.*` event.\n\nThe flow must be published with the \"API / webhook\" trigger (`startable_via_api: true`). Its first message follows WhatsApp's rules: outside the 24-hour window that means an approved template.\n","x-required-scopes":["flows:trigger"],"x-test-mode":"unsupported","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","resource_missing","flow_not_triggerable","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to"],"properties":{"to":{"type":"string","description":"The customer's phone, in any format."},"variables":{"type":"object"},"reference":{"type":"string","maxLength":190}}},"example":{"to":"+966501234567","variables":{"order_id":"10482","delivery_date":"الخميس"},"reference":"order-10482"}}}},"responses":{"201":{"description":"The run, already under way.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRun"},"example":{"id":"run_9021","object":"flow_run","flow_id":"flow_18","customer":{"contact_id":"ct_1052","address":"+966501234567"},"channel":"whatsapp","state":"waiting_input","current_step":"node_ask_rating","reference":"order-10482","variables":{"order_id":"10482","delivery_date":"الخميس","first_name":"سارة","reference":"order-10482"},"started_at":"2026-10-01T10:00:00Z","completed_at":null,"updated_at":"2026-10-01T10:00:01Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}},"get":{"operationId":"listFlowRuns","tags":["Flows"],"summary":"List a flow's runs","x-required-scopes":["flows:read"],"x-test-mode":"unsupported","x-errors":["resource_missing","parameter_invalid","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"state","in":"query","schema":{"type":"string","enum":["active","waiting_input","paused","handed_off","completed","expired"]}},{"name":"to","in":"query","description":"Only this customer's runs (phone, any format).","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of runs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FlowRunList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/me":{"get":{"operationId":"getMe","tags":["Account"],"summary":"Check your API key","description":"Returns the workspace, the key's mode and scopes, and your rate limit. The quickest way to confirm a key works.","x-required-scopes":[],"x-test-mode":"supported","x-errors":["api_key_missing","api_key_invalid","api_key_revoked","api_key_expired","rate_limited"],"responses":{"200":{"description":"The key works.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyContext"},"example":{"object":"api_key_context","livemode":false,"workspace":{"id":"ws_12","name":"Riyadh Coffee"},"api_key":{"id":"key_7","name":"Order system","prefix":"sk_test_Ab12Cd","scopes":["messages:send","messages:read","webhooks:read","webhooks:write"],"expires_at":null},"rate_limit":{"limit":60,"window_seconds":60}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/media":{"post":{"operationId":"uploadMedia","tags":["Media"],"summary":"Upload a file","description":"Adds a file to the workspace media library and gives it a permanent public URL. Send its `id` as the `media_id` of an `image`, `video`, `audio`, `document` or `sticker` message, as often as you like.\n\nSend the file as `multipart/form-data` with the `type` it will be sent as. WhatsApp's limits are checked here, before anything is sent: images JPEG/PNG up to 5 MB, video MP4/3GPP up to 16 MB, audio up to 16 MB, documents up to 100 MB, stickers WebP up to 100 KB (500 KB animated).\n","x-required-scopes":["media:write"],"x-test-mode":"supported","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","media_invalid","quota_exceeded","payload_too_large","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","type"],"properties":{"file":{"type":"string","format":"binary"},"type":{"type":"string","enum":["image","video","audio","document","sticker"]}}}}}},"responses":{"201":{"description":"Uploaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Media"},"example":{"id":"med_381","object":"media","type":"image","filename":"shoe-front.png","mime_type":"image/png","size_bytes":482113,"url":"https://api.example.com/media/3f9a0c1b2d4e5f60718293a4b5c6d7e8f9012345/shoe-front.png","created_at":"2026-10-01T09:00:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"The media library is full.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Invalid"}}},"get":{"operationId":"listMedia","tags":["Media"],"summary":"List files","x-required-scopes":["media:read"],"x-test-mode":"supported","x-errors":["parameter_invalid","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"type","in":"query","schema":{"type":"string","enum":["image","video","audio","document","sticker"]}}],"responses":{"200":{"description":"A page of files.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/media/{id}":{"get":{"operationId":"getMedia","tags":["Media"],"summary":"Get a file","x-required-scopes":["media:read"],"x-test-mode":"supported","x-errors":["resource_missing","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The file's details and public URL.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Media"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteMedia","tags":["Media"],"summary":"Delete a file","description":"Deletes the file and its public URL at once. If saved messages or templates still use it, the answer is `resource_in_use` listing them; add `?force=true` to delete anyway. Needs a live key, because the library is your live one.","x-required-scopes":["media:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","resource_in_use","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"},{"name":"force","in":"query","schema":{"type":"boolean","default":false}}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"},"example":{"id":"med_381","object":"media","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Still used by saved messages or templates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/members":{"get":{"operationId":"listMembers","tags":["Conversations"],"summary":"List team members","description":"The people in this workspace, to assign conversations to. Viewers can read the inbox but cannot be assigned.","x-required-scopes":["conversations:read"],"x-test-mode":"supported","x-errors":["parameter_invalid","rate_limited"],"parameters":[{"name":"role","in":"query","schema":{"type":"string","enum":["owner","admin","editor","viewer","customer_service"]}}],"responses":{"200":{"description":"Every member.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberList"},"example":{"object":"list","data":[{"id":"usr_41","object":"member","name":"نورة العتيبي","email":"noura@example.com","role":"customer_service"}],"has_more":false,"next_cursor":null}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/messages":{"post":{"operationId":"sendMessage","tags":["Messages"],"summary":"Send a message","description":"One endpoint for every kind of message: set `type` and put the content under a key of the same name: `text`, `template`, `image`, `video`, `audio`, `document`, `sticker`, `location`, `contacts`, `interactive` (reply buttons, lists, link buttons, location requests) or `reaction`.\n\n- **Inside 24 hours** of the customer's last message you can send any type.\n- **Outside that window** (or to start a conversation) only an approved `template` is delivered. Anything else returns `window_closed`.\n- **Instagram and Messenger** (`channel`) take replies only: text and media, inside the 24 hours.\n\nThe response comes back as soon as the channel accepts the message (`status: accepted`). Delivery and read updates arrive as `message.*` webhook events. With a test key, the message is simulated and never reaches WhatsApp.\n","x-required-scopes":["messages:send"],"x-test-mode":"simulated","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","resource_missing","window_closed","template_not_found","template_not_approved","template_variables_mismatch","recipient_not_consented","sender_not_configured","sender_not_sendable","channel_not_connected","channel_error","test_mode_unsupported","quota_exceeded","subscription_inactive","api_access_not_in_plan","idempotency_key_reused","idempotency_in_progress","send_outcome_unknown","platform_paused","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessage"},"examples":{"text":{"summary":"Text reply","value":{"to":"+966501234567","type":"text","text":{"body":"أهلًا سارة! طلبك جاهز للاستلام 🎉"},"reference":"order-10482"}},"template":{"summary":"Approved template","value":{"to":"+966501234567","type":"template","template":{"name":"order_update","language":"ar","variables":{"body":["سارة","#10482"]}},"reference":"order-10482"}},"reply":{"summary":"Reply to a customer message","value":{"to":"+966501234567","type":"text","text":{"body":"تم، سنتواصل معك خلال دقائق."},"reply_to":"imsg_88213"}},"document":{"summary":"PDF invoice","value":{"to":"+966501234567","type":"document","document":{"link":"https://files.example.com/invoices/10482.pdf","filename":"invoice-10482.pdf","caption":"فاتورة طلبك رقم 10482"}}},"image":{"summary":"Uploaded image","value":{"to":"+966501234567","type":"image","image":{"media_id":"med_381","caption":"هذه صورة منتجك قبل الشحن 📦"}}},"video":{"summary":"Video by link","value":{"to":"+966501234567","type":"video","video":{"link":"https://files.example.com/guides/setup.mp4","caption":"طريقة تركيب الجهاز في دقيقة"}}},"audio":{"summary":"Voice note","value":{"to":"+966501234567","type":"audio","audio":{"media_id":"med_412"}}},"sticker":{"summary":"Sticker","value":{"to":"+966501234567","type":"sticker","sticker":{"link":"https://files.example.com/stickers/thanks.webp"}}},"contacts":{"summary":"Contact card","value":{"to":"+966501234567","type":"contacts","contacts":[{"name":{"formatted_name":"خدمة العملاء","first_name":"خدمة العملاء"},"phones":[{"phone":"+966112345678","type":"WORK","wa_id":"966112345678"}],"org":{"company":"متجر النخبة"}}]}},"buttons":{"summary":"Reply buttons","value":{"to":"+966501234567","type":"interactive","interactive":{"type":"button","body":"هل تؤكد موعدك غدًا الساعة 4 عصرًا؟","footer":"عيادة النخبة","buttons":[{"id":"confirm_10482","title":"تأكيد"},{"id":"reschedule_10482","title":"تغيير الموعد"}]}}},"list":{"summary":"List of options","value":{"to":"+966501234567","type":"interactive","interactive":{"type":"list","body":"اختر الفرع الأقرب لك","button":"الفروع","sections":[{"title":"الرياض","rows":[{"id":"br_olaya","title":"فرع العليا","description":"يوميًا 9 ص – 11 م"},{"id":"br_malqa","title":"فرع الملقا"}]},{"title":"جدة","rows":[{"id":"br_tahlia","title":"فرع التحلية"}]}]}}},"cta_url":{"summary":"Link button","value":{"to":"+966501234567","type":"interactive","interactive":{"type":"cta_url","body":"طلبك في الطريق. تابع الشحنة لحظة بلحظة.","display_text":"تتبّع الطلب","url":"https://shop.example.com/track/10482"}}},"location":{"summary":"Location pin","value":{"to":"+966501234567","type":"location","location":{"latitude":24.6958,"longitude":46.6853,"name":"فرع العليا","address":"طريق العليا، الرياض"}}},"reaction":{"summary":"React to a message","value":{"to":"+966501234567","type":"reaction","reaction":{"message_id":"imsg_88213","emoji":"👍"}}},"instagram":{"summary":"Instagram reply","value":{"channel":"instagram","to":"17841400000000000","type":"text","text":{"body":"شكرًا لتواصلك! المقاس متوفر ✨"}}}}}}},"responses":{"202":{"description":"Accepted by WhatsApp (or by the simulator, in test mode).","headers":{"Idempotent-Replayed":{"description":"`true` when this is the stored response of an earlier request with the same Idempotency-Key.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"},"example":{"id":"msg_48213","object":"message","livemode":true,"direction":"outbound","channel":"whatsapp","from":"+966112345678","to":"+966501234567","type":"text","text":{"body":"أهلًا سارة! طلبك جاهز للاستلام 🎉"},"status":"accepted","error":null,"reference":"order-10482","conversation_id":"conv_311","provider_message_id":"wamid.HBgMOTY2NTAxMjM0NTY3FQIAERgSMEM4","created_at":"2026-10-01T09:30:00Z","updated_at":"2026-10-01T09:30:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"The recipient has not consented, or an earlier request with this Idempotency-Key is still running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Not sendable as asked, e.g. the 24-hour window is closed or the template is not approved.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"invalid_request_error","code":"window_closed","message":"The 24-hour customer service window is closed. Send an approved template instead.","param":"type","last_inbound_at":"2026-09-29T08:12:00+00:00","window_expires_at":"2026-09-30T08:12:00+00:00","doc_url":"https://app.example.com/docs/errors#window_closed","request_id":"req_01j9x3k2m4n5p6q7r8s9t0v1w2"}}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"listMessages","tags":["Messages"],"summary":"List messages sent through the API","description":"Newest first. Live keys list messages sent with the API; test keys list test-mode messages (sent and simulated inbound).","x-required-scopes":["messages:read"],"x-test-mode":"supported","x-errors":["parameter_invalid","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"reference","in":"query","description":"Only the messages you sent with this `reference`.","schema":{"type":"string"}},{"name":"to","in":"query","description":"Only messages to this number (E.164).","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/messages/{id}":{"get":{"operationId":"getMessage","tags":["Messages"],"summary":"Get a message","description":"A message and its current status. Works for messages you sent (`msg_…`) and customer messages from webhook events (`imsg_…`).","x-required-scopes":["messages:read"],"x-test-mode":"supported","x-errors":["resource_missing","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/messages/{id}/read":{"post":{"operationId":"markMessageRead","tags":["Messages"],"summary":"Mark a customer message as read","description":"Shows the customer blue ticks on their message (and on everything they sent before it). Add `typing_indicator: true` to also show \"typing…\" while you prepare the answer: it lasts up to 25 seconds, or until you reply.\n\nWorks on WhatsApp messages you received (`imsg_…`, from `message.received` events).\n","x-required-scopes":["messages:send"],"x-test-mode":"simulated","x-errors":["resource_missing","sender_not_configured","channel_error","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"typing_indicator":{"type":"boolean","default":false,"description":"Also show \"typing…\" to the customer."}}},"example":{"typing_indicator":true}}}},"responses":{"200":{"description":"The customer now sees the message as read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadReceipt"},"example":{"object":"read_receipt","message_id":"imsg_88213","livemode":true,"typing_indicator":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}}},"/numbers":{"get":{"operationId":"listNumbers","tags":["Numbers"],"summary":"List your WhatsApp numbers","description":"The numbers this workspace sends from, with their quality rating, daily limit and whether they can send right now. Use an `id` as `from` when sending.","x-required-scopes":["numbers:read"],"x-test-mode":"supported","x-errors":["parameter_invalid","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"}],"responses":{"200":{"description":"A page of numbers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumberList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/numbers/{id}":{"get":{"operationId":"getNumber","tags":["Numbers"],"summary":"Get a number","description":"One number and its health. When `can_send` is `false`, `cannot_send_reason` says why (disconnected, token needs reconnecting…); fix it in Settings → WhatsApp.","x-required-scopes":["numbers:read"],"x-test-mode":"supported","x-errors":["resource_missing","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"},"example":{"id":"num_3","object":"phone_number","phone_number":"+966112345678","display_name":"متجر النخبة","name_status":"APPROVED","is_default":true,"quality_rating":"green","messaging_limit_tier":"TIER_1K","daily_conversation_limit":1000,"can_send":true,"cannot_send_reason":null,"created_at":"2026-06-01T10:00:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/tags":{"get":{"operationId":"listTags","tags":["Contacts"],"summary":"List tags","description":"The tags that group your contacts, with how many WhatsApp contacts carry each one.","x-required-scopes":["contacts:read"],"x-test-mode":"supported","x-errors":["parameter_invalid","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"name","in":"query","description":"The exact tag name.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of tags.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagList"},"example":{"object":"list","data":[{"id":"tag_12","object":"tag","name":"عملاء VIP","contact_count":348,"created_at":"2026-07-01T09:00:00Z"}],"has_more":false,"next_cursor":null}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createTag","tags":["Contacts"],"summary":"Create a tag","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-idempotent":true,"x-errors":["parameter_missing","resource_exists","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":255}}},"example":{"name":"عملاء VIP"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A tag with this name exists; `existing_id` names it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/tags/{id}":{"patch":{"operationId":"updateTag","tags":["Contacts"],"summary":"Rename a tag","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","resource_exists","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":255}}},"example":{"name":"عملاء ذهبيون"}}}},"responses":{"200":{"description":"Renamed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Tag"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}},"delete":{"operationId":"deleteTag","tags":["Contacts"],"summary":"Delete a tag","description":"Removes the tag from every contact. The contacts stay.","x-required-scopes":["contacts:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"},"example":{"id":"tag_12","object":"tag","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/templates":{"get":{"operationId":"listTemplates","tags":["Templates"],"summary":"List templates","description":"Your WhatsApp message templates. Each one says what it needs filled in (`variables`) and carries a `send_example` you can paste into `POST /v1/messages`.","x-required-scopes":["templates:read"],"x-test-mode":"supported","x-errors":["parameter_invalid","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"status","in":"query","schema":{"type":"string","enum":["approved","pending","rejected","paused","disabled","draft"]}},{"name":"category","in":"query","schema":{"type":"string","enum":["marketing","utility","authentication"]}},{"name":"language","in":"query","description":"A language code, e.g. `ar` or `en_US`.","schema":{"type":"string"}},{"name":"name","in":"query","description":"The exact template name.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of templates.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createTemplate","tags":["Templates"],"summary":"Create a template","description":"Submits a new template to WhatsApp for approval. It comes back `pending`; WhatsApp usually decides within minutes (sometimes up to 24 hours), and you get `template.status_changed` when it does.\n\n`components` are WhatsApp's own: `HEADER`, `BODY` (required), `FOOTER`, `BUTTONS`. Every `{{n}}` placeholder needs an `example` value, or WhatsApp rejects the template. The builder's own checks run first (lengths, button counts, the language list, name unique per WhatsApp account), so most mistakes come back at once as `parameter_invalid`.\n\nFor an image, video or document header, upload the file with `POST /v1/media` and put its `med_…` id in `example.header_handle`: we hand it to WhatsApp for you, and the template then sends with that file by default.\n\nAuthentication (OTP) templates take `otp` instead of `components`, need a plan with OTP verification, and a business verified by Meta.\n","x-required-scopes":["templates:write"],"x-test-mode":"unsupported","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","resource_exists","resource_missing","sender_not_configured","capability_disabled","channel_error","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateInput"},"examples":{"utility":{"summary":"Order update with a tracking button","value":{"name":"order_shipped","language":"ar","category":"utility","components":[{"type":"BODY","text":"مرحبًا {{1}}، شُحن طلبك رقم {{2}} وسيصلك خلال يومين.","example":{"body_text":[["سارة","10482"]]}},{"type":"BUTTONS","buttons":[{"type":"URL","text":"تتبّع الشحنة","url":"https://shop.example.com/track/{{1}}","example":["https://shop.example.com/track/10482"]}]}]}},"marketing":{"summary":"Offer with an image","value":{"name":"weekend_offer","language":"ar","category":"marketing","components":[{"type":"HEADER","format":"IMAGE","example":{"header_handle":["med_381"]}},{"type":"BODY","text":"خصم {{1}} على كل الطلبات هذا الأسبوع 🎉","example":{"body_text":[["20٪"]]}},{"type":"FOOTER","text":"للإلغاء أرسل \"إيقاف\""}]}}}}}},"responses":{"201":{"description":"Submitted to WhatsApp; `status` is `pending`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A template with this name and language exists on the number's WhatsApp account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/Invalid"}}}},"/templates/{id}":{"get":{"operationId":"getTemplate","tags":["Templates"],"summary":"Get a template","description":"One template, its components as WhatsApp approved them, and for a rejected template WhatsApp's reason when it gave one.","x-required-scopes":["templates:read"],"x-test-mode":"supported","x-errors":["resource_missing","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The template.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"},"example":{"id":"tpl_27","object":"template","name":"order_update","language":"ar","category":"utility","status":"approved","rejection_reason":null,"components":[{"type":"BODY","text":"مرحبًا {{1}}، طلبك {{2}} في الطريق."},{"type":"BUTTONS","buttons":[{"type":"URL","text":"تتبّع الطلب","url":"https://shop.example.com/track/{{1}}"}]}],"variables":{"body":2,"buttons":[{"index":0,"type":"url"}]},"send_example":{"type":"template","template":{"name":"order_update","language":"ar","variables":{"body":["value 1","value 2"],"buttons":[{"url_suffix":"value"}]}}},"created_at":"2026-08-01T10:00:00Z","updated_at":"2026-08-02T07:30:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteTemplate","tags":["Templates"],"summary":"Delete a template","description":"Deletes the template here and at WhatsApp. Refused with `resource_in_use` while a scheduled or running campaign uses it. WhatsApp does not let the same name be reused for 30 days.","x-required-scopes":["templates:write"],"x-test-mode":"unsupported","x-errors":["resource_missing","resource_in_use","test_mode_unsupported","rate_limited"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Deleted"},"example":{"id":"tpl_27","object":"template","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A scheduled or running campaign uses it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/test/inbound_messages":{"post":{"operationId":"simulateInboundMessage","tags":["Test mode"],"summary":"Simulate a customer message","description":"As if a customer had just written to you. Fires `message.received` to your test endpoints and opens the simulated 24-hour window for that number. Test keys only.","x-required-scopes":["messages:send"],"x-test-mode":"only","x-errors":["parameter_missing","parameter_invalid"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulateInbound"},"example":{"from":"+966500000004","type":"text","text":{"body":"مرحبا، أين طلبي؟"},"profile_name":"Sara"}}}},"responses":{"201":{"description":"The simulated inbound message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/Invalid"}}}},"/test/messages/{id}/status":{"post":{"operationId":"simulateMessageStatus","tags":["Test mode"],"summary":"Force a message status","description":"Move a test message to `sent`, `delivered`, `read` or `failed` now and fire the matching event. Statuses only move forward. Test keys only.","x-required-scopes":["messages:send"],"x-test-mode":"only","x-errors":["resource_missing","parameter_invalid"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulateStatus"},"example":{"status":"failed","error_code":"131026"}}}},"responses":{"200":{"description":"The message with its new status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}}},"/usage":{"get":{"operationId":"getUsage","tags":["Usage"],"summary":"Get usage","description":"What the workspace has used this billing period against its plan (marketing and service messages, campaigns, contacts, templates, flows, numbers), and how this key's mode has called the API over the last 30 days.\n\nCheck `remaining` before a large send to avoid a `quota_exceeded`. `limit` and `remaining` are `null` for an unlimited allowance.\n","x-required-scopes":["usage:read"],"x-test-mode":"supported","x-errors":["rate_limited"],"responses":{"200":{"description":"The usage report.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"},"example":{"object":"usage","period":{"start":"2026-10-01T00:00:00Z","end":"2026-11-01T00:00:00Z"},"allowances":[{"key":"marketing_messages_month","type":"monthly","used":4120,"limit":10000,"remaining":5880},{"key":"service_messages_month","type":"monthly","used":18230,"limit":null,"remaining":null},{"key":"contacts","type":"total","used":9214,"limit":25000,"remaining":15786}],"api":{"livemode":true,"window_days":30,"requests":48213,"errors":212,"error_rate":0.0044,"by_day":[{"date":"2026-09-30","requests":1804,"errors":6}]}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/webhook_deliveries/{id}/retry":{"post":{"operationId":"retryWebhookDelivery","tags":["Webhooks"],"summary":"Retry a delivery now","description":"Sends the same event again (same `webhook-id`, fresh signature), e.g. after you fixed your server.","x-required-scopes":["webhooks:write"],"x-test-mode":"supported","x-errors":["resource_missing"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"202":{"description":"Queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhook_endpoints":{"get":{"operationId":"listWebhookEndpoints","tags":["Webhooks"],"summary":"List webhook endpoints","description":"The endpoints in the key's mode (live keys see live endpoints, test keys test endpoints).","x-required-scopes":["webhooks:read"],"x-test-mode":"supported","x-errors":["rate_limited"],"responses":{"200":{"description":"The endpoints.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createWebhookEndpoint","tags":["Webhooks"],"summary":"Add a webhook endpoint","description":"We will POST each subscribed event to `url` as JSON, signed with the [Standard Webhooks](https://www.standardwebhooks.com) scheme. The response includes the signing `secret` **once**: store it to verify signatures.\n\nIn production the URL must be `https://` and publicly reachable. Up to 10 endpoints per workspace.\n\nAn event carries the same data its read endpoint returns, so each event family needs that read scope: `message.*` needs `messages:read`, `contact.*` `contacts:read`, `conversation.*` `conversations:read`, `campaign.*` `campaigns:read`, `flow.*` `flows:read`, `template.*` `templates:read`. `[\"*\"]` needs all of them. The same check applies when you change the URL or events of an endpoint.\n","x-required-scopes":["webhooks:write"],"x-test-mode":"supported","x-idempotent":true,"x-errors":["parameter_missing","parameter_invalid","webhook_url_invalid","webhook_endpoint_limit","insufficient_scope","rate_limited"],"parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","enabled_events"],"properties":{"url":{"type":"string","format":"uri","description":"Where to send events."},"enabled_events":{"type":"array","items":{"type":"string"},"description":"Event types from `GET /v1/event_types`, a whole group such as `contact.*`, or `[\"*\"]` for all."},"description":{"type":"string","maxLength":255}}},"example":{"url":"https://example.com/webhooks/whatsapp","enabled_events":["message.received","message.delivered","message.read","message.failed"],"description":"Order system"}}}},"responses":{"201":{"description":"Created. `secret` is shown only now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"},"example":{"id":"we_01j9x3k2m4n5p6q7r8s9t0v1w2","object":"webhook_endpoint","livemode":true,"url":"https://example.com/webhooks/whatsapp","description":"Order system","enabled_events":["message.received","message.delivered","message.read","message.failed"],"status":"enabled","disabled_reason":null,"secret_preview":"whsec_…K3x=","secret":"whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw/kNEBw0UXK3x=","created_at":"2026-10-01T09:30:00Z","updated_at":"2026-10-01T09:30:00Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/Invalid"}}}},"/webhook_endpoints/{id}":{"get":{"operationId":"getWebhookEndpoint","tags":["Webhooks"],"summary":"Get a webhook endpoint","x-required-scopes":["webhooks:read"],"x-test-mode":"supported","x-errors":["resource_missing"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateWebhookEndpoint","tags":["Webhooks"],"summary":"Update a webhook endpoint","description":"Change the URL or events, or pause it with `\"disabled\": true`. Re-enabling clears the failure count.","x-required-scopes":["webhooks:write"],"x-test-mode":"supported","x-errors":["resource_missing","parameter_invalid","webhook_url_invalid","insufficient_scope"],"parameters":[{"$ref":"#/components/parameters/Id"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"enabled_events":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"disabled":{"type":"boolean"}}},"example":{"enabled_events":["*"]}}}},"responses":{"200":{"description":"The updated endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}},"delete":{"operationId":"deleteWebhookEndpoint","tags":["Webhooks"],"summary":"Delete a webhook endpoint","description":"Stops all deliveries to it, including pending retries.","x-required-scopes":["webhooks:write"],"x-test-mode":"supported","x-errors":["resource_missing"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"type":"object","required":["id","object","deleted"],"properties":{"id":{"type":"string"},"object":{"const":"webhook_endpoint"},"deleted":{"const":true}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhook_endpoints/{id}/deliveries":{"get":{"operationId":"listWebhookDeliveries","tags":["Webhooks"],"summary":"List deliveries","description":"Every attempt to deliver an event to this endpoint, newest first, with the HTTP status your server answered.","x-required-scopes":["webhooks:read"],"x-test-mode":"supported","x-errors":["resource_missing"],"parameters":[{"$ref":"#/components/parameters/Id"},{"$ref":"#/components/parameters/Limit"},{"$ref":"#/components/parameters/Cursor"},{"name":"status","in":"query","description":"Only deliveries in this state.","schema":{"type":"string","enum":["pending","succeeded","failed","dead"]}}],"responses":{"200":{"description":"A page of deliveries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhook_endpoints/{id}/rotate_secret":{"post":{"operationId":"rotateWebhookSecret","tags":["Webhooks"],"summary":"Rotate the signing secret","description":"Returns a new `secret`. For 24 hours every event is signed with both the old and the new secret, so you can deploy the new one without missing events.","x-required-scopes":["webhooks:write"],"x-test-mode":"supported","x-errors":["resource_missing"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"200":{"description":"The endpoint, with its new secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/webhook_endpoints/{id}/test":{"post":{"operationId":"testWebhookEndpoint","tags":["Webhooks"],"summary":"Send a test event","description":"Sends a signed `webhook.test` event to this endpoint only. Check the delivery with the deliveries endpoint.","x-required-scopes":["webhooks:write"],"x-test-mode":"supported","x-errors":["resource_missing","parameter_invalid"],"parameters":[{"$ref":"#/components/parameters/Id"}],"responses":{"202":{"description":"The test event was queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_… / sk_test_…","description":"Send your secret key as `Authorization: Bearer sk_live_…` (or `sk_test_…` in test mode). Create keys in Developers → API keys."}},"responses":{"Unauthorized":{"description":"The API key is missing, invalid, revoked or expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"authentication_error","code":"api_key_invalid","message":"The API key is not valid.","doc_url":"https://app.example.com/docs/errors#api_key_invalid","request_id":"req_01j9x3k2m4n5p6q7r8s9t0v1w2"}}}}},"Forbidden":{"description":"The key lacks a scope, the plan has no API access, or the request is not available in this mode.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"permission_error","code":"insufficient_scope","message":"This API key does not have the \"messages:send\" scope. Create a key with it in Developers > API keys.","required_scope":"messages:send","doc_url":"https://app.example.com/docs/errors#insufficient_scope","request_id":"req_01j9x3k2m4n5p6q7r8s9t0v1w2"}}}}},"NotFound":{"description":"No such object in this workspace (and mode).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"invalid_request_error","code":"resource_missing","message":"No such message: msg_999.","param":"id","doc_url":"https://app.example.com/docs/errors#resource_missing","request_id":"req_01j9x3k2m4n5p6q7r8s9t0v1w2"}}}}},"Invalid":{"description":"The request is not valid. `details` lists each bad field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"type":"invalid_request_error","code":"parameter_missing","message":"The to field is required.","param":"to","details":[{"param":"to","code":"parameter_missing","message":"The to field is required."}],"doc_url":"https://app.example.com/docs/errors#parameter_missing","request_id":"req_01j9x3k2m4n5p6q7r8s9t0v1w2"}}}}},"RateLimited":{"description":"Too many requests. Wait for the seconds in `Retry-After`.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"parameters":{"Id":{"name":"id","in":"path","required":true,"description":"The object's id.","schema":{"type":"string"}},"Limit":{"name":"limit","in":"query","description":"How many objects to return, 1 to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},"Cursor":{"name":"cursor","in":"query","description":"The `next_cursor` from the previous page.","schema":{"type":"string"}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","description":"Any unique string (a UUID is ideal). Retrying with the same key and body returns the first response instead of acting twice. Remembered for 24 hours.","schema":{"type":"string","maxLength":255}}},"schemas":{"Error":{"type":"object","description":"Every error the API returns has this shape.","required":["error"],"properties":{"error":{"type":"object","required":["type","code","message","doc_url"],"properties":{"type":{"type":"string","enum":["authentication_error","permission_error","invalid_request_error","billing_error","rate_limit_error","api_error"],"description":"The broad kind of error."},"code":{"type":"string","description":"A stable, machine-readable code. Branch on this, never on `message`."},"message":{"type":"string","description":"A human-readable explanation, in English."},"param":{"type":"string","description":"The request field the error is about, when there is one."},"doc_url":{"type":"string","format":"uri","description":"Where this code is explained, with how to fix it."},"request_id":{"type":"string","description":"The id of this request (also in the `Request-Id` header). Quote it to support."},"details":{"type":"array","description":"One entry per invalid field, when several are wrong.","items":{"type":"object","required":["param","code","message"],"properties":{"param":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}},"channel_error":{"type":"object","description":"The messaging channel's own error, when WhatsApp rejected the message.","properties":{"provider":{"type":"string"},"code":{"type":["integer","null"]},"subcode":{"type":["integer","null"]},"title":{"type":["string","null"]},"message":{"type":["string","null"]}}}},"additionalProperties":true}}},"ApiKeyContext":{"type":"object","required":["object","livemode","workspace","api_key","rate_limit"],"properties":{"object":{"const":"api_key_context"},"livemode":{"type":"boolean","description":"`false` for a test key: sends are simulated and never reach WhatsApp."},"workspace":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","examples":["ws_12"]},"name":{"type":["string","null"]}}},"api_key":{"type":"object","required":["id","name","prefix","scopes"],"properties":{"id":{"type":"string","examples":["key_7"]},"name":{"type":"string"},"prefix":{"type":"string","examples":["sk_test_Ab12Cd"]},"scopes":{"type":"array","items":{"type":"string"}},"expires_at":{"type":["string","null"],"format":"date-time"}}},"rate_limit":{"type":"object","required":["limit","window_seconds"],"properties":{"limit":{"type":"integer"},"window_seconds":{"type":"integer"}}}}},"Message":{"type":"object","description":"A message you sent or a customer sent you. The content sits under a key named after `type` (e.g. `text`, `template`).","required":["id","object","livemode","direction","channel","type","status","created_at"],"properties":{"id":{"type":"string","description":"Unique id. Opaque: store it as a string of up to 64 characters.","examples":["msg_48213"]},"object":{"const":"message"},"livemode":{"type":"boolean"},"direction":{"type":"string","enum":["outbound","inbound"],"description":"`outbound` for messages you send, `inbound` for customer messages."},"channel":{"type":"string","enum":["whatsapp","instagram","messenger"]},"from":{"type":["string","null"],"description":"Sender, in E.164 for WhatsApp.","examples":["+966112345678"]},"to":{"type":["string","null"],"description":"Recipient, in E.164 for WhatsApp.","examples":["+966501234567"]},"type":{"type":"string","description":"What kind of content the message carries.","examples":["text"]},"text":{"type":"object","properties":{"body":{"type":"string"}}},"template":{"type":"object","properties":{"name":{"type":"string"},"language":{"type":"string"},"variables":{"type":"object"},"body":{"type":"string"}}},"image":{"type":"object","description":"Media messages carry `link` (or `media_id`), `caption`, `filename` and `mime_type` when known."},"video":{"type":"object"},"audio":{"type":"object"},"document":{"type":"object"},"sticker":{"type":"object"},"location":{"type":"object"},"contacts":{"type":"array"},"interactive":{"type":"object","description":"What you sent (`type`, `body`, `buttons`…), or for a customer's tap, `reply: {id, title}`."},"reaction":{"type":"object"},"status":{"type":"string","enum":["accepted","sent","delivered","read","failed","received"],"description":"`accepted` → `sent` → `delivered` → `read`, or `failed`. Customer messages are `received`. Status changes arrive as webhook events."},"error":{"type":["object","null"],"description":"Why delivery failed, when `status` is `failed`.","properties":{"code":{"type":["string","null"]},"title":{"type":["string","null"]},"message":{"type":["string","null"]}}},"reference":{"type":["string","null"],"description":"Your own reference, echoed back from the send request and in every event."},"conversation_id":{"type":["string","null"]},"provider_message_id":{"type":["string","null"],"description":"WhatsApp's own message id (wamid)."},"contact":{"type":["object","null"],"properties":{"name":{"type":["string","null"]}}},"context":{"type":["object","null"],"description":"For a reply, the message being replied to.","properties":{"provider_message_id":{"type":"string"}}},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}},"additionalProperties":true},"MessageList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}}}]},"ListEnvelope":{"type":"object","description":"Every list is paginated with a cursor. Pass `next_cursor` as `cursor` to get the next page.","required":["object","data","has_more","next_cursor"],"properties":{"object":{"const":"list"},"data":{"type":"array"},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"SendMessageBase":{"type":"object","required":["to","type"],"properties":{"channel":{"type":"string","enum":["whatsapp","instagram","messenger"],"default":"whatsapp","description":"Where to send. Instagram and Messenger take replies only (text, image, video, audio, document) within 24 hours of the customer's last message; `to` is then the customer id from their message's `from`."},"to":{"type":"string","description":"The customer's phone number in E.164, e.g. `+966501234567`. On Instagram / Messenger, the customer id from their message."},"from":{"type":"string","description":"Which of your numbers sends it: a number id (`num_…`) or the number in E.164. Default: the number the customer last wrote to, else your default number."},"reply_to":{"type":"string","description":"Send as a reply to this message (a `msg_…` / `imsg_…` id or a WhatsApp wamid)."},"reference":{"type":"string","maxLength":128,"description":"Your own id for this message (an order number, a ticket). Returned in the response and in every webhook event about it."}}},"SendTextMessage":{"title":"Text","description":"A plain text message. Only inside the 24-hour window after the customer's last message.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","text"],"properties":{"type":{"const":"text"},"text":{"type":"object","required":["body"],"properties":{"body":{"type":"string","maxLength":4096,"description":"The message text. Up to 4096 characters; Arabic and emoji are fine."},"preview_url":{"type":"boolean","default":false,"description":"Show a preview of the first link in the text."}}}}}]},"SendTemplateMessage":{"title":"Template","description":"An approved WhatsApp template. The only way to start a conversation or write after the 24-hour window.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","template"],"properties":{"type":{"const":"template"},"template":{"type":"object","properties":{"name":{"type":"string","description":"The template's name, as approved by WhatsApp."},"language":{"type":"string","description":"Language code, e.g. `ar` or `en_US`. Required when the name exists in several languages."},"id":{"type":"string","description":"The template id (`tpl_…`), instead of name + language."},"variables":{"type":"object","description":"Values for the placeholders: `body` (in order: {{1}}, {{2}}…), `header_text`, `header_media_link`, and `buttons` by index (`url_suffix`, `coupon_code`, `payload`).","properties":{"body":{"type":"array","items":{"type":"string"}},"header_text":{"type":"string"},"header_media_link":{"type":"string","format":"uri"},"buttons":{"type":"object"}}}}},"consent_confirmed":{"type":"boolean","default":false,"description":"Required as `true` to send a non-authentication template to a contact who has not agreed to receive business messages. Each confirmation is recorded in the audit log."}}}]},"SendImageMessage":{"title":"Image","description":"A JPEG or PNG image, up to 5 MB.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","image"],"properties":{"type":{"const":"image"},"image":{"type":"object","properties":{"link":{"type":"string","format":"uri","description":"A public https:// URL WhatsApp downloads the file from. Send `link` or `media_id`."},"media_id":{"type":"string","description":"A file you uploaded with `POST /v1/media` (`med_…`)."},"caption":{"type":"string","maxLength":1024,"description":"Text shown under the file."}}}}}]},"SendVideoMessage":{"title":"Video","description":"An MP4 or 3GPP video, up to 16 MB.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","video"],"properties":{"type":{"const":"video"},"video":{"type":"object","properties":{"link":{"type":"string","format":"uri","description":"A public https:// URL WhatsApp downloads the file from. Send `link` or `media_id`."},"media_id":{"type":"string","description":"A file you uploaded with `POST /v1/media` (`med_…`)."},"caption":{"type":"string","maxLength":1024,"description":"Text shown under the file."}}}}}]},"SendAudioMessage":{"title":"Audio","description":"An audio file (AAC, MP4, MPEG, AMR, OGG/Opus), up to 16 MB. No caption.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","audio"],"properties":{"type":{"const":"audio"},"audio":{"type":"object","properties":{"link":{"type":"string","format":"uri","description":"A public https:// URL WhatsApp downloads the file from. Send `link` or `media_id`."},"media_id":{"type":"string","description":"A file you uploaded with `POST /v1/media` (`med_…`)."}}}}}]},"SendDocumentMessage":{"title":"Document","description":"Any file up to 100 MB, e.g. a PDF invoice.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","document"],"properties":{"type":{"const":"document"},"document":{"type":"object","properties":{"link":{"type":"string","format":"uri","description":"A public https:// URL WhatsApp downloads the file from. Send `link` or `media_id`."},"media_id":{"type":"string","description":"A file you uploaded with `POST /v1/media` (`med_…`)."},"caption":{"type":"string","maxLength":1024,"description":"Text shown under the file."},"filename":{"type":"string","maxLength":240,"description":"The file name the customer sees, e.g. `invoice-10482.pdf`."}}}}}]},"SendStickerMessage":{"title":"Sticker","description":"A WebP sticker, 512×512, up to 100 KB (500 KB animated). WhatsApp only.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","sticker"],"properties":{"type":{"const":"sticker"},"sticker":{"type":"object","properties":{"link":{"type":"string","format":"uri","description":"A public https:// URL WhatsApp downloads the file from. Send `link` or `media_id`."},"media_id":{"type":"string","description":"A file you uploaded with `POST /v1/media` (`med_…`)."}}}}}]},"SendLocationMessage":{"title":"Location","description":"A pin on the map, e.g. your branch.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","location"],"properties":{"type":{"const":"location"},"location":{"type":"object","required":["latitude","longitude"],"properties":{"latitude":{"type":"number","minimum":-90,"maximum":90},"longitude":{"type":"number","minimum":-180,"maximum":180},"name":{"type":"string","description":"The place's name, e.g. `Olaya branch`."},"address":{"type":"string"}}}}}]},"SendContactsMessage":{"title":"Contacts","description":"One or more contact cards the customer can save with one tap.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","contacts"],"properties":{"type":{"const":"contacts"},"contacts":{"type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"type":"object","required":["formatted_name"],"properties":{"formatted_name":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"}}},"phones":{"type":"array","items":{"type":"object","required":["phone"],"properties":{"phone":{"type":"string"},"type":{"type":"string","enum":["CELL","MAIN","IPHONE","HOME","WORK"]},"wa_id":{"type":"string","description":"The number's WhatsApp id (digits). Adds a \"Message\" button to the card."}}}},"emails":{"type":"array","items":{"type":"object","required":["email"],"properties":{"email":{"type":"string"},"type":{"type":"string","enum":["HOME","WORK"]}}}},"org":{"type":"object","properties":{"company":{"type":"string"},"department":{"type":"string"},"title":{"type":"string"}}},"urls":{"type":"array","items":{"type":"object","required":["url"],"properties":{"url":{"type":"string"},"type":{"type":"string","enum":["HOME","WORK"]}}}},"birthday":{"type":"string","format":"date"}}}}}}]},"InteractiveHeader":{"type":"object","required":["type"],"description":"Optional. Reply buttons and lists take a `text` header; a URL button can also show an `image`, `video` or `document` from a `link`.","properties":{"type":{"type":"string","enum":["text","image","video","document"]},"text":{"type":"string","maxLength":60},"link":{"type":"string","format":"uri"}}},"SendInteractiveMessage":{"title":"Interactive","description":"Messages the customer answers with a tap: up to 3 reply `button`s, a `list` of up to 10 options, a `cta_url` button that opens a link, or a `location_request`. Each tap arrives as a `message.received` event of type `interactive` carrying the `id` you chose.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","interactive"],"properties":{"type":{"const":"interactive"},"interactive":{"type":"object","required":["type","body"],"properties":{"type":{"type":"string","enum":["button","list","cta_url","location_request"]},"header":{"$ref":"#/components/schemas/InteractiveHeader"},"body":{"type":"string","maxLength":4096,"description":"The message text. Up to 1024 characters (4096 for a list)."},"footer":{"type":"string","maxLength":60},"buttons":{"type":"array","description":"For `button`: 1–3 buttons. `id` (up to 256 characters) comes back to you when tapped; `title` (up to 20) is what the customer sees.","items":{"type":"object","required":["id","title"],"properties":{"id":{"type":"string","maxLength":256},"title":{"type":"string","maxLength":20}}}},"button":{"type":"string","maxLength":20,"description":"For `list`: the label of the button that opens the list."},"sections":{"type":"array","description":"For `list`: 1–10 sections, at most 10 rows in total. With more than one section, each needs a `title`.","items":{"type":"object","required":["rows"],"properties":{"title":{"type":"string","maxLength":24},"rows":{"type":"array","items":{"type":"object","required":["id","title"],"properties":{"id":{"type":"string","maxLength":200},"title":{"type":"string","maxLength":24},"description":{"type":"string","maxLength":72}}}}}}},"display_text":{"type":"string","maxLength":20,"description":"For `cta_url`: the button label."},"url":{"type":"string","format":"uri","description":"For `cta_url`: the https:// page the button opens."}}}}}]},"SendReactionMessage":{"title":"Reaction","description":"React to a message with an emoji. Send an empty `emoji` to remove your reaction. Free, and not counted as a message.","allOf":[{"$ref":"#/components/schemas/SendMessageBase"},{"type":"object","required":["type","reaction"],"properties":{"type":{"const":"reaction"},"reaction":{"type":"object","required":["message_id","emoji"],"properties":{"message_id":{"type":"string","description":"The message to react to (`imsg_…`, `msg_…` or a WhatsApp wamid)."},"emoji":{"type":"string","examples":["👍"]}}}}}]},"SendMessage":{"oneOf":[{"$ref":"#/components/schemas/SendTextMessage"},{"$ref":"#/components/schemas/SendTemplateMessage"},{"$ref":"#/components/schemas/SendImageMessage"},{"$ref":"#/components/schemas/SendVideoMessage"},{"$ref":"#/components/schemas/SendAudioMessage"},{"$ref":"#/components/schemas/SendDocumentMessage"},{"$ref":"#/components/schemas/SendStickerMessage"},{"$ref":"#/components/schemas/SendLocationMessage"},{"$ref":"#/components/schemas/SendContactsMessage"},{"$ref":"#/components/schemas/SendInteractiveMessage"},{"$ref":"#/components/schemas/SendReactionMessage"}],"discriminator":{"propertyName":"type","mapping":{"text":"#/components/schemas/SendTextMessage","template":"#/components/schemas/SendTemplateMessage","image":"#/components/schemas/SendImageMessage","video":"#/components/schemas/SendVideoMessage","audio":"#/components/schemas/SendAudioMessage","document":"#/components/schemas/SendDocumentMessage","sticker":"#/components/schemas/SendStickerMessage","location":"#/components/schemas/SendLocationMessage","contacts":"#/components/schemas/SendContactsMessage","interactive":"#/components/schemas/SendInteractiveMessage","reaction":"#/components/schemas/SendReactionMessage"}}},"WebhookEndpoint":{"type":"object","required":["id","object","livemode","url","enabled_events","status","created_at"],"properties":{"id":{"type":"string","examples":["we_01j9x3k2m4n5p6q7r8s9t0v1w2"]},"object":{"const":"webhook_endpoint"},"livemode":{"type":"boolean","description":"Live endpoints get live events; test endpoints get test-mode events. Never both."},"url":{"type":"string","format":"uri"},"description":{"type":["string","null"]},"enabled_events":{"type":"array","items":{"type":"string"},"description":"Event types to send, a whole group such as `contact.*`, or `[\"*\"]` for all."},"status":{"type":"string","enum":["enabled","disabled","auto_disabled"],"description":"`auto_disabled` after 3 days of failed deliveries or a `410 Gone` answer."},"disabled_reason":{"type":["string","null"]},"secret_preview":{"type":"string"},"secret":{"type":"string","description":"The signing secret (`whsec_…`). Returned only when the endpoint is created or its secret rotated. Store it now."},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"WebhookEndpointList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}}}]},"WebhookDelivery":{"type":"object","required":["id","object","livemode","webhook_endpoint_id","event_id","event_type","status","attempts"],"properties":{"id":{"type":"string","examples":["del_01j9x3k2m4n5p6q7r8s9t0v1w2"]},"object":{"const":"webhook_delivery"},"livemode":{"type":"boolean"},"webhook_endpoint_id":{"type":"string"},"event_id":{"type":"string"},"event_type":{"type":"string"},"status":{"type":"string","enum":["pending","succeeded","failed","dead"],"description":"`failed` will be retried at `next_attempt_at`; `dead` will not be retried again."},"attempts":{"type":"integer"},"http_status":{"type":["integer","null"]},"duration_ms":{"type":["integer","null"]},"response_snippet":{"type":["string","null"]},"last_error":{"type":["string","null"]},"next_attempt_at":{"type":["string","null"],"format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":["string","null"],"format":"date-time"},"payload":{"$ref":"#/components/schemas/Event"}}},"WebhookDeliveryList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}}}]},"EventType":{"type":"object","required":["object","type","description"],"properties":{"object":{"const":"event_type"},"type":{"type":"string","examples":["message.delivered"]},"object_type":{"type":"string"},"description":{"type":"string"}},"additionalProperties":true},"EventTypeList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EventType"}}}}]},"Event":{"type":"object","description":"The body of every webhook request. `data.object` is exactly the resource the REST API returns (e.g. a `message`).","required":["id","object","type","version","created_at","livemode","workspace_id","data"],"properties":{"id":{"type":"string","description":"Event id, also sent as the `webhook-id` header. The same on every retry, so use it to ignore duplicates.","examples":["evt_01j9x3k2m4n5p6q7r8s9t0v1w2"]},"object":{"const":"event"},"type":{"type":"string","examples":["message.delivered"]},"version":{"type":"string","description":"Payload version. Fields are only ever added within a version.","examples":["2"]},"created_at":{"type":"string","format":"date-time"},"livemode":{"type":"boolean"},"workspace_id":{"type":"string","examples":["ws_12"]},"data":{"type":"object","required":["object"],"properties":{"object":{"type":"object"},"previous_attributes":{"type":"object","description":"The values that changed, as they were before, when known."}}}}},"SimulateInbound":{"type":"object","required":["from"],"properties":{"from":{"type":"string","description":"The customer number the message comes from, in E.164."},"to":{"type":"string"},"type":{"type":"string","enum":["text","button_reply"]},"text":{"type":"object","properties":{"body":{"type":"string"}}},"button_reply":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"}}},"profile_name":{"type":"string"}}},"SimulateStatus":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["sent","delivered","read","failed"]},"error_code":{"type":"string"},"error_message":{"type":"string"}}},"ReadReceipt":{"type":"object","required":["object","message_id","livemode"],"properties":{"object":{"const":"read_receipt"},"message_id":{"type":"string"},"livemode":{"type":"boolean"},"typing_indicator":{"type":"boolean"}}},"Deleted":{"type":"object","required":["id","object","deleted"],"properties":{"id":{"type":"string"},"object":{"type":"string"},"deleted":{"const":true}}},"PhoneNumber":{"type":"object","required":["id","object","phone_number","is_default","can_send"],"properties":{"id":{"type":"string","examples":["num_3"]},"object":{"const":"phone_number"},"phone_number":{"type":"string","examples":["+966112345678"]},"display_name":{"type":["string","null"]},"name_status":{"type":["string","null"],"description":"Whether WhatsApp approved the display name."},"is_default":{"type":"boolean","description":"Sends by default when `from` is left out and the customer has no thread on another number."},"quality_rating":{"type":["string","null"],"description":"WhatsApp's quality rating, `green`, `yellow` or `red`. Red numbers risk a lower daily limit."},"messaging_limit_tier":{"type":["string","null"],"examples":["TIER_1K"]},"daily_conversation_limit":{"type":["integer","null"],"description":"Business-initiated conversations per 24 hours; `null` means unlimited or not yet known."},"can_send":{"type":"boolean"},"cannot_send_reason":{"type":["string","null"]},"created_at":{"type":["string","null"],"format":"date-time"}}},"PhoneNumberList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PhoneNumber"}}}}]},"Template":{"type":"object","required":["id","object","name","language","status","components","variables","send_example"],"properties":{"id":{"type":"string","examples":["tpl_27"]},"object":{"const":"template"},"name":{"type":"string"},"language":{"type":["string","null"]},"category":{"type":["string","null"],"enum":["marketing","utility","authentication",null]},"status":{"type":"string","description":"Only `approved` templates can be sent."},"rejection_reason":{"type":["string","null"]},"components":{"type":"array","description":"HEADER, BODY, FOOTER and BUTTONS, exactly as WhatsApp holds them."},"variables":{"type":"object","description":"What a send must fill in: `header` (the header type that needs a value), `body` (how many {{n}} placeholders) and `buttons` (which buttons take a value).","properties":{"header":{"type":"string"},"body":{"type":"integer"},"buttons":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"type":{"type":"string"}}}}}},"send_example":{"type":"object","description":"A `POST /v1/messages` body for this template with placeholder values. Add `to` and your values."},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"TemplateList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Template"}}}}]},"Tag":{"type":"object","required":["id","object","name"],"properties":{"id":{"type":"string","examples":["tag_12"]},"object":{"const":"tag"},"name":{"type":"string"},"contact_count":{"type":"integer"},"created_at":{"type":["string","null"],"format":"date-time"}}},"TagList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tag"}}}}]},"ContactField":{"type":"object","required":["id","object","key","label","type","required"],"properties":{"id":{"type":"string","examples":["fld_4"]},"object":{"const":"contact_field"},"key":{"type":"string","examples":["loyalty_points"]},"label":{"type":"string"},"type":{"type":"string","enum":["text","number","date","select"]},"options":{"type":["array","null"],"description":"The allowed values of a `select` field."},"required":{"type":"boolean"}}},"ContactFieldList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ContactField"}}}}]},"Flow":{"type":"object","required":["id","object","name","status","startable_via_api"],"properties":{"id":{"type":"string","examples":["flow_18"]},"object":{"const":"flow"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["draft","published","archived"]},"trigger":{"type":["string","null"],"description":"What starts the flow, e.g. `webhook`, `keyword`, `inbound-message`, `contact-added`."},"startable_via_api":{"type":"boolean"},"number_id":{"type":["string","null"]},"published_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"FlowList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Flow"}}}}]},"Member":{"type":"object","required":["id","object","role"],"properties":{"id":{"type":"string","examples":["usr_41"]},"object":{"const":"member"},"name":{"type":["string","null"]},"email":{"type":["string","null"]},"role":{"type":"string","enum":["owner","admin","editor","viewer","customer_service"]}}},"MemberList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Member"}}}}]},"Media":{"type":"object","required":["id","object","type","url","size_bytes"],"properties":{"id":{"type":"string","examples":["med_381"]},"object":{"const":"media"},"type":{"type":"string","enum":["image","video","audio","document","sticker"]},"filename":{"type":["string","null"]},"mime_type":{"type":["string","null"]},"size_bytes":{"type":"integer"},"url":{"type":"string","format":"uri","description":"A permanent, public, unguessable link. Anyone with it can open the file."},"created_at":{"type":["string","null"],"format":"date-time"}}},"MediaList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Media"}}}}]},"Contact":{"type":"object","required":["id","object","phone","opted_in","tags","fields"],"properties":{"id":{"type":"string","examples":["ct_1052"]},"object":{"const":"contact"},"phone":{"type":["string","null"],"examples":["+966501234567"]},"email":{"type":["string","null"]},"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"language":{"type":["string","null"],"description":"The language they prefer, e.g. `ar` or `en`."},"country":{"type":["string","null"]},"city":{"type":["string","null"]},"gender":{"type":["string","null"]},"birth_date":{"type":["string","null"],"format":"date"},"notes":{"type":["string","null"]},"opted_in":{"type":"boolean","description":"`false` once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need `consent_confirmed`."},"consent":{"type":["object","null"],"description":"How and when they agreed to business messages, when recorded.","properties":{"source":{"type":"string"},"note":{"type":"string"},"captured_at":{"type":"string","format":"date-time"}}},"opted_out_at":{"type":["string","null"],"format":"date-time"},"bot_enabled":{"type":"boolean","description":"Whether automated replies (flows, AI bots) answer them."},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}}},"fields":{"type":"object","description":"Custom field values by key. Values are strings."},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"ContactList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}}}}]},"ContactUpdate":{"type":"object","properties":{"phone":{"type":"string","description":"Any format; stored as E.164. Saudi numbers written locally (`0501234567`) are understood."},"email":{"type":["string","null"],"format":"email"},"first_name":{"type":["string","null"]},"last_name":{"type":["string","null"]},"language":{"type":["string","null"]},"country":{"type":["string","null"]},"city":{"type":["string","null"]},"gender":{"type":["string","null"],"enum":["male","female","other","prefer_not_to_say",null]},"birth_date":{"type":["string","null"],"format":"date"},"notes":{"type":["string","null"]},"bot_enabled":{"type":"boolean"},"tags":{"type":"array","items":{"type":"string"},"description":"Tag ids (`tag_…`) or names. A name that does not exist is created."},"fields":{"type":"object","description":"Custom field values by key, checked against the field's type (number, date as YYYY-MM-DD, or one of a select's options)."},"opted_in":{"type":"boolean"},"consent":{"type":"object","required":["source"],"description":"How they agreed: `website_form`, `paper_form`, `existing_customer`, `whatsapp_conversation`, or `other` with a `note`.","properties":{"source":{"type":"string","enum":["website_form","paper_form","existing_customer","whatsapp_conversation","other"]},"note":{"type":"string","maxLength":200}}}}},"ContactInput":{"allOf":[{"$ref":"#/components/schemas/ContactUpdate"},{"type":"object","required":["phone"]}]},"Conversation":{"type":"object","required":["id","object","channel","customer","state","open"],"properties":{"id":{"type":"string","examples":["conv_311"]},"object":{"const":"conversation"},"channel":{"type":"string","enum":["whatsapp","instagram","messenger"]},"customer":{"type":"object","properties":{"contact_id":{"type":["string","null"]},"address":{"type":"string","description":"The phone (E.164) on WhatsApp; the customer's id on Instagram / Messenger. Send replies `to` this."},"name":{"type":["string","null"]}}},"number_id":{"type":["string","null"]},"state":{"type":"string","enum":["bot","needs_agent","assigned","human","resolved","snoozed"],"description":"`bot` the automation is answering; `needs_agent` waiting for a person; `assigned` handed to someone who has not replied yet; `human` a person is on it; `snoozed` parked until `snoozed_until`; `resolved` closed."},"open":{"type":"boolean"},"assignee":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":["string","null"]}}},"unread":{"type":"boolean"},"label":{"type":["string","null"]},"last_customer_message_at":{"type":["string","null"],"format":"date-time"},"last_agent_message_at":{"type":["string","null"],"format":"date-time"},"reply_window_expires_at":{"type":["string","null"],"format":"date-time","description":"After this, only an approved template can reach the customer (WhatsApp) or nothing until they write (Instagram / Messenger)."},"resolved_at":{"type":["string","null"],"format":"date-time"},"snoozed_until":{"type":["string","null"],"format":"date-time"},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"ConversationList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Conversation"}}}}]},"TemplateInput":{"type":"object","required":["name","language","category"],"properties":{"name":{"type":"string","description":"Lowercase letters, digits and underscores, e.g. `order_shipped`."},"language":{"type":"string","examples":["ar"]},"category":{"type":"string","enum":["marketing","utility","authentication"]},"number_id":{"type":"string","description":"Which number's WhatsApp account holds the template. Default: your default number."},"components":{"type":"array","description":"WhatsApp template components (HEADER, BODY, FOOTER, BUTTONS), each `{{n}}` with an `example`."},"otp":{"type":"object","description":"For `authentication`: `button_text` (e.g. \"Copy code\"), optional `code_expiration_minutes` and `show_security_recommendation`."}}},"Campaign":{"type":"object","required":["id","object","name","status","stats"],"properties":{"id":{"type":"string","examples":["cmp_64"]},"object":{"const":"campaign"},"name":{"type":"string"},"description":{"type":["string","null"]},"status":{"type":"string","enum":["draft","scheduled","in_progress","paused","completed","failed","cancelled"],"description":"`draft` until started; `scheduled` waits for `scheduled_at`; `paused` is held (see `hold_reason`): fix the cause, then `POST /v1/campaigns/{id}/resume`."},"hold_reason":{"type":["string","null"]},"template":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"language":{"type":["string","null"]}}},"number_id":{"type":["string","null"]},"scheduled_at":{"type":["string","null"],"format":"date-time"},"timezone":{"type":["string","null"]},"stats":{"type":"object","description":"Recipient counts. `GET /v1/campaigns/{id}` adds `pending`, `replied` and the rates.","properties":{"recipients":{"type":"integer"},"pending":{"type":"integer"},"sent":{"type":"integer"},"delivered":{"type":"integer"},"read":{"type":"integer"},"failed":{"type":"integer"},"replied":{"type":"integer"},"delivery_rate":{"type":["number","null"]},"read_rate":{"type":["number","null"]},"reply_rate":{"type":["number","null"]}}},"estimated_cost":{"type":["object","null"],"description":"What WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.","properties":{"currency":{"type":"string"},"total":{"type":"number"},"total_usd":{"type":"number"},"recipients_priced":{"type":"integer"},"recipients_free":{"type":"integer"},"recipients_unpriced":{"type":"integer"}}},"created_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"CampaignList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Campaign"}}}}]},"CampaignInput":{"type":"object","required":["name","template","audience"],"properties":{"name":{"type":"string","maxLength":255},"description":{"type":"string"},"template":{"type":"object","description":"`{\"id\": \"tpl_…\"}`, or `{\"name\": …, \"language\": …}`. Must be approved.","properties":{"id":{"type":"string"},"name":{"type":"string"},"language":{"type":"string"}}},"number_id":{"type":"string","description":"The sending number. Required when the workspace has more than one."},"audience":{"type":"object","properties":{"contacts":{"type":"array","items":{"type":"string"}},"tags":{"type":"array","items":{"type":"string"}},"all_contacts":{"type":"boolean"}}},"variables":{"type":"object","description":"The template's variables (as in `POST /v1/messages`), with per-recipient placeholders such as `{{first_name}}`."},"scheduled_at":{"type":"string","description":"A future local date-time, read in `timezone`. Leave out to send at start."},"timezone":{"type":"string","examples":["Asia/Riyadh"]},"link_tracking":{"type":"boolean","description":"Count clicks on the template's URL buttons."},"consent_confirmed":{"type":"boolean"}}},"FlowRun":{"type":"object","required":["id","object","flow_id","state"],"properties":{"id":{"type":"string","examples":["run_9021"]},"object":{"const":"flow_run"},"flow_id":{"type":"string"},"customer":{"type":"object","properties":{"contact_id":{"type":["string","null"]},"address":{"type":["string","null"]}}},"channel":{"type":"string"},"state":{"type":"string","enum":["active","waiting_input","paused","handed_off","completed","expired"],"description":"`waiting_input` waits for the customer; `paused` waits for a delay step; `handed_off` passed to your team; `expired` gave up waiting."},"current_step":{"type":["string","null"]},"reference":{"type":["string","null"]},"variables":{"type":"object"},"started_at":{"type":["string","null"],"format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"updated_at":{"type":["string","null"],"format":"date-time"}}},"FlowRunList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FlowRun"}}}}]},"FlowResponse":{"type":"object","required":["id","object","answers"],"properties":{"id":{"type":"string","examples":["fres_77"]},"object":{"const":"flow_response"},"whatsapp_flow_id":{"type":["string","null"]},"flow_name":{"type":["string","null"]},"customer":{"type":"object","properties":{"contact_id":{"type":["string","null"]},"address":{"type":["string","null"]}}},"campaign_id":{"type":["string","null"]},"template_id":{"type":["string","null"]},"answers":{"type":"object","description":"The form's fields and what the customer entered, by the field names set in the WhatsApp Flow."},"file_count":{"type":"integer"},"submitted_at":{"type":["string","null"],"format":"date-time"}}},"FlowResponseList":{"allOf":[{"$ref":"#/components/schemas/ListEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/FlowResponse"}}}}]},"Usage":{"type":"object","required":["object","period","allowances","api"],"properties":{"object":{"const":"usage"},"period":{"type":"object","properties":{"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"}}},"allowances":{"type":"array","items":{"type":"object","required":["key","type","used"],"properties":{"key":{"type":"string","description":"e.g. `marketing_messages_month`, `service_messages_month`, `campaigns_month`, `contacts`, `message_templates`, `active_flows`, `whatsapp_numbers`."},"type":{"type":"string","enum":["monthly","total"],"description":"`monthly` resets each billing period; `total` counts what exists now."},"used":{"type":"integer"},"limit":{"type":["integer","null"]},"remaining":{"type":["integer","null"]}}}},"api":{"type":"object","properties":{"livemode":{"type":["boolean","null"]},"window_days":{"type":"integer"},"requests":{"type":"integer"},"errors":{"type":"integer"},"error_rate":{"type":"number"},"by_day":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"requests":{"type":"integer"},"errors":{"type":"integer"}}}}}}}}}},"webhooks":{"message.received":{"post":{"operationId":"event_message_received","summary":"message.received","description":"A customer sent a message to one of your numbers. `data.object` is the inbound `message`.","x-event-object":"message","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"},"example":{"id":"evt_01j9x7q8r9s0t1v2w3x4y5z6a7","object":"event","type":"message.received","version":"2","created_at":"2026-10-01T09:29:12Z","livemode":true,"workspace_id":"ws_12","data":{"object":{"id":"imsg_88213","object":"message","livemode":true,"direction":"inbound","channel":"whatsapp","from":"+966501234567","to":"+966112345678","type":"text","text":{"body":"مرحبا، أين طلبي؟"},"status":"received","error":null,"reference":null,"conversation_id":null,"provider_message_id":"wamid.HBgMOTY2NTAxMjM0NTY3FQIAEhgUM0E","contact":{"name":"Sara"},"context":null,"created_at":"2026-10-01T09:29:10Z","updated_at":"2026-10-01T09:29:12Z"}}}}}},"responses":{"200":{"description":"Answer any 2xx within 15 seconds to acknowledge. Anything else is retried."}}}},"message.sent":{"post":{"operationId":"event_message_sent","summary":"message.sent","description":"WhatsApp sent your message. `data.previous_attributes.status` is the status before.","x-event-object":"message","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"message.delivered":{"post":{"operationId":"event_message_delivered","summary":"message.delivered","description":"Your message reached the customer's phone.","x-event-object":"message","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"},"example":{"id":"evt_01j9x7r2m3n4p5q6r7s8t9v0w1","object":"event","type":"message.delivered","version":"2","created_at":"2026-10-01T09:30:04Z","livemode":true,"workspace_id":"ws_12","data":{"object":{"id":"msg_48213","object":"message","livemode":true,"direction":"outbound","channel":"whatsapp","from":"+966112345678","to":"+966501234567","type":"text","text":{"body":"أهلًا سارة! طلبك جاهز للاستلام 🎉"},"status":"delivered","error":null,"reference":"order-10482","conversation_id":"conv_311","provider_message_id":"wamid.HBgMOTY2NTAxMjM0NTY3FQIAERgSMEM4","created_at":"2026-10-01T09:30:00Z","updated_at":"2026-10-01T09:30:04Z"},"previous_attributes":{"status":"sent"}}}}}},"responses":{"200":{"description":"Acknowledged."}}}},"message.read":{"post":{"operationId":"event_message_read","summary":"message.read","description":"The customer opened your message. Only sent when the customer shares read receipts.","x-event-object":"message","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"message.failed":{"post":{"operationId":"event_message_failed","summary":"message.failed","description":"Your message could not be delivered. `data.object.error` carries WhatsApp's code and reason (e.g. 131026 undeliverable, 131047 outside the 24-hour window).","x-event-object":"message","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"contact.created":{"post":{"operationId":"event_contact_created","summary":"contact.created","description":"A WhatsApp contact was added, from the portal, an import, a flow or the API. `data.object` is the `contact` with its tags and custom fields.","x-event-object":"contact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"},"example":{"id":"evt_01j9x8a1b2c3d4e5f6g7h8j9k0","object":"event","type":"contact.created","version":"2","created_at":"2026-10-01T10:02:03Z","livemode":true,"workspace_id":"ws_12","data":{"object":{"id":"ct_1052","object":"contact","phone":"+966501234567","email":"sara@example.com","first_name":"سارة","last_name":"القحطاني","language":"ar","country":"SA","city":"الرياض","gender":null,"birth_date":null,"notes":null,"opted_in":true,"consent":{"source":"website_form","captured_at":"2026-10-01T10:02:00Z"},"opted_out_at":null,"bot_enabled":true,"tags":[{"id":"tag_12","name":"عملاء VIP"}],"fields":{"loyalty_points":"120"},"created_at":"2026-10-01T10:02:00Z","updated_at":"2026-10-01T10:02:00Z"}}}}}},"responses":{"200":{"description":"Acknowledged."}}}},"contact.updated":{"post":{"operationId":"event_contact_updated","summary":"contact.updated","description":"A contact's details, tags or custom fields changed. Several quick changes to one contact arrive as one event carrying the final state.","x-event-object":"contact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"contact.deleted":{"post":{"operationId":"event_contact_deleted","summary":"contact.deleted","description":"A contact was deleted. `data.object` is `{id, object: \"contact\", deleted: true}`: the details are gone, so delete your copy too.","x-event-object":"contact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"},"example":{"id":"evt_01j9x8b1c2d3e4f5g6h7j8k9m0","object":"event","type":"contact.deleted","version":"2","created_at":"2026-10-02T08:00:00Z","livemode":true,"workspace_id":"ws_12","data":{"object":{"id":"ct_1052","object":"contact","deleted":true}}}}}},"responses":{"200":{"description":"Acknowledged."}}}},"contact.opted_out":{"post":{"operationId":"event_contact_opted_out","summary":"contact.opted_out","description":"A contact asked to stop receiving business messages (they sent STOP, or someone opted them out). Queued campaign messages to them are cancelled; stop messaging them from your systems too.","x-event-object":"contact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"contact.opted_in":{"post":{"operationId":"event_contact_opted_in","summary":"contact.opted_in","description":"A contact who had opted out agreed again to business messages (they sent START, or their consent was recorded). `consent.source` says how.","x-event-object":"contact","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"template.status_changed":{"post":{"operationId":"event_template_status_changed","summary":"template.status_changed","description":"WhatsApp approved, rejected, paused or disabled one of your templates. `data.object` is the `template`; `data.previous_attributes.status` is where it was; `rejection_reason` says why when WhatsApp gave a reason.","x-event-object":"template","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"campaign.started":{"post":{"operationId":"event_campaign_started","summary":"campaign.started","description":"A campaign started sending, or was scheduled to. `data.object` is the `campaign`.","x-event-object":"campaign","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"campaign.paused":{"post":{"operationId":"event_campaign_paused","summary":"campaign.paused","description":"A campaign was held, for example because Meta limited the sending number. `hold_reason` says why; resume it with `POST /v1/campaigns/{id}/resume` once the cause is fixed. `data.object` is the `campaign`.","x-event-object":"campaign","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"campaign.resumed":{"post":{"operationId":"event_campaign_resumed","summary":"campaign.resumed","description":"A held campaign is sending again. `data.object` is the `campaign`.","x-event-object":"campaign","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"campaign.completed":{"post":{"operationId":"event_campaign_completed","summary":"campaign.completed","description":"A campaign finished: every recipient was sent to or failed. `stats` has the final numbers. `data.object` is the `campaign`.","x-event-object":"campaign","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"campaign.failed":{"post":{"operationId":"event_campaign_failed","summary":"campaign.failed","description":"A campaign could not be sent, for example because Meta blocked delivery for a billing reason. `data.object` is the `campaign`.","x-event-object":"campaign","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"campaign.cancelled":{"post":{"operationId":"event_campaign_cancelled","summary":"campaign.cancelled","description":"A campaign was cancelled; its unsent messages will not go out. `data.object` is the `campaign`.","x-event-object":"campaign","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"flow.run.started":{"post":{"operationId":"event_flow_run_started","summary":"flow.run.started","description":"A flow started for a customer, from the API, a trigger or the inbox. `data.object` is the `flow_run`.","x-event-object":"flow_run","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"flow.run.handed_off":{"post":{"operationId":"event_flow_run_handed_off","summary":"flow.run.handed_off","description":"A flow handed the customer to your team; the conversation now needs a person. `data.object` is the `flow_run`.","x-event-object":"flow_run","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"flow.run.completed":{"post":{"operationId":"event_flow_run_completed","summary":"flow.run.completed","description":"A flow reached its end for a customer. `variables` holds everything it collected. `data.object` is the `flow_run`.","x-event-object":"flow_run","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"flow.run.expired":{"post":{"operationId":"event_flow_run_expired","summary":"flow.run.expired","description":"A flow stopped waiting for a customer who did not answer in time. `data.object` is the `flow_run`.","x-event-object":"flow_run","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"flow.response":{"post":{"operationId":"event_flow_response","summary":"flow.response","description":"A customer submitted a WhatsApp Flow form. `answers` holds what they entered. `data.object` is the `flow_response`.","x-event-object":"flow_response","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"conversation.created":{"post":{"operationId":"event_conversation_created","summary":"conversation.created","description":"A customer started a new conversation with the workspace. `data.object` is the `conversation`.","x-event-object":"conversation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"conversation.needs_agent":{"post":{"operationId":"event_conversation_needs_agent","summary":"conversation.needs_agent","description":"A conversation is waiting for a person, because the bot handed it over or the customer asked for someone. Page your team, or assign it with `POST /v1/conversations/{id}/assign`.","x-event-object":"conversation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"},"example":{"id":"evt_01j9x9c1d2e3f4g5h6j7k8m9n0","object":"event","type":"conversation.needs_agent","version":"2","created_at":"2026-10-01T09:29:15Z","livemode":true,"workspace_id":"ws_12","data":{"object":{"id":"conv_311","object":"conversation","channel":"whatsapp","customer":{"contact_id":"ct_1052","address":"+966501234567","name":"سارة القحطاني"},"number_id":"num_3","state":"needs_agent","open":true,"assignee":null,"unread":true,"label":null,"last_customer_message_at":"2026-10-01T09:29:10Z","last_agent_message_at":null,"reply_window_expires_at":"2026-10-02T09:29:10Z","resolved_at":null,"snoozed_until":null,"created_at":"2026-10-01T09:28:00Z","updated_at":"2026-10-01T09:29:12Z"}}}}}},"responses":{"200":{"description":"Acknowledged."}}}},"conversation.assigned":{"post":{"operationId":"event_conversation_assigned","summary":"conversation.assigned","description":"A conversation was assigned to a team member (`assignee`), by a person, a rule or the API.","x-event-object":"conversation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"conversation.resolved":{"post":{"operationId":"event_conversation_resolved","summary":"conversation.resolved","description":"A conversation was resolved. A good moment to send a satisfaction survey or close the ticket in your helpdesk.","x-event-object":"conversation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"conversation.reopened":{"post":{"operationId":"event_conversation_reopened","summary":"conversation.reopened","description":"A resolved conversation became active again, usually because the customer wrote.","x-event-object":"conversation","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}},"webhook.test":{"post":{"operationId":"event_webhook_test","summary":"webhook.test","description":"Sent when you press \"Send test event\" (or call the test endpoint). Carries no customer data.","x-event-object":"webhook_test","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"responses":{"200":{"description":"Acknowledged."}}}}},"x-errors":[{"code":"api_key_missing","status":401,"en":{"title":"No API key","fix":"Send your key in the header `Authorization: Bearer sk_live_…` (or `sk_test_…`)."},"ar":{"title":"لا يوجد مفتاح API","fix":"أرسل مفتاحك في الترويسة `Authorization: Bearer sk_live_…` (أو `sk_test_…`)."}},{"code":"api_key_invalid","status":401,"en":{"title":"Invalid API key","fix":"Copy the key again from Developers → API keys. Keys start with `sk_live_` or `sk_test_`."},"ar":{"title":"مفتاح API غير صالح","fix":"انسخ المفتاح مرة أخرى من المطورين ← مفاتيح API. تبدأ المفاتيح بـ `sk_live_` أو `sk_test_`."}},{"code":"api_key_revoked","status":401,"en":{"title":"Key revoked","fix":"Someone revoked this key. Create a new one in Developers → API keys."},"ar":{"title":"المفتاح ملغى","fix":"ألغى أحدهم هذا المفتاح. أنشئ مفتاحًا جديدًا من المطورين ← مفاتيح API."}},{"code":"api_key_expired","status":401,"en":{"title":"Key expired","fix":"The key passed its expiry date. Create a new one."},"ar":{"title":"انتهت صلاحية المفتاح","fix":"تجاوز المفتاح تاريخ انتهائه. أنشئ مفتاحًا جديدًا."}},{"code":"subscription_inactive","status":402,"en":{"title":"Subscription not active","fix":"Renew the workspace subscription in Billing. Reads keep working meanwhile."},"ar":{"title":"الاشتراك غير نشط","fix":"جدّد اشتراك مساحة العمل من الفوترة. تبقى عمليات القراءة متاحة خلال ذلك."}},{"code":"quota_exceeded","status":402,"en":{"title":"Allowance used up","fix":"The plan's allowance for this period is used. Upgrade or add an add-on in Billing. `entitlement` names the allowance."},"ar":{"title":"نفد الرصيد المتاح","fix":"استُهلك رصيد الباقة لهذه الفترة. قم بالترقية أو أضف إضافة من الفوترة. يوضّح `entitlement` الرصيد المقصود."}},{"code":"insufficient_scope","status":403,"en":{"title":"Missing permission","fix":"The key lacks the scope in `required_scope`. Create a key that has it."},"ar":{"title":"صلاحية ناقصة","fix":"المفتاح لا يملك الصلاحية الموجودة في `required_scope`. أنشئ مفتاحًا يملكها."}},{"code":"api_access_not_in_plan","status":403,"en":{"title":"API not in plan","fix":"Live API access needs a plan that includes it. Test keys work on every plan."},"ar":{"title":"الواجهة غير مشمولة في الباقة","fix":"يتطلب الوصول الحي للواجهة باقة تشمله. مفاتيح الاختبار تعمل في كل الباقات."}},{"code":"workspace_suspended","status":403,"en":{"title":"Workspace suspended","fix":"Contact support to reactivate the workspace."},"ar":{"title":"مساحة العمل موقوفة","fix":"تواصل مع الدعم لإعادة تفعيل مساحة العمل."}},{"code":"capability_disabled","status":403,"en":{"title":"Capability turned off","fix":"This capability is turned off for the workspace. Contact support."},"ar":{"title":"الميزة موقوفة","fix":"هذه الميزة موقوفة لمساحة العمل. تواصل مع الدعم."}},{"code":"test_mode_unsupported","status":403,"en":{"title":"Not in test mode","fix":"This request acts on real customer data and has no simulated version. Use a live key, or a separate workspace for staging."},"ar":{"title":"غير متاح في وضع الاختبار","fix":"هذا الطلب يعمل على بيانات عملاء حقيقية ولا توجد له نسخة محاكاة. استخدم مفتاح تشغيل، أو مساحة عمل منفصلة للتجربة."}},{"code":"invalid_json","status":400,"en":{"title":"Invalid JSON","fix":"The body is not valid JSON. Check quotes and commas, and send `Content-Type: application/json`."},"ar":{"title":"JSON غير صالح","fix":"جسم الطلب ليس JSON صالحًا. راجع علامات الاقتباس والفواصل، وأرسل `Content-Type: application/json`."}},{"code":"parameter_missing","status":422,"en":{"title":"Missing parameter","fix":"`param` names the missing field; `details` lists all of them."},"ar":{"title":"حقل مفقود","fix":"يسمّي `param` الحقل المفقود، ويسرد `details` كل الحقول."}},{"code":"parameter_invalid","status":422,"en":{"title":"Invalid parameter","fix":"`param` names the field; `message` says what is wrong with it."},"ar":{"title":"حقل غير صالح","fix":"يسمّي `param` الحقل، ويوضح `message` ما الخطأ فيه."}},{"code":"resource_missing","status":404,"en":{"title":"Not found","fix":"No object with that id in this workspace. Test-mode ids (`msg_test_…`) are readable only with a test key, and live ids only with a live key."},"ar":{"title":"غير موجود","fix":"لا يوجد عنصر بهذا المعرّف في مساحة العمل. معرّفات الاختبار (`msg_test_…`) تُقرأ بمفتاح اختبار فقط، والمعرّفات الحية بمفتاح تشغيل فقط."}},{"code":"route_not_found","status":404,"en":{"title":"Unknown URL","fix":"Check the path and method against the API reference. All paths start with `/v1/`."},"ar":{"title":"رابط غير معروف","fix":"راجع المسار والطريقة في مرجع الواجهة. كل المسارات تبدأ بـ `/v1/`."}},{"code":"method_not_allowed","status":405,"en":{"title":"Wrong HTTP method","fix":"This URL exists but not with this method. See the API reference."},"ar":{"title":"طريقة HTTP خاطئة","fix":"الرابط موجود لكن ليس بهذه الطريقة. راجع مرجع الواجهة."}},{"code":"payload_too_large","status":413,"en":{"title":"Body too large","fix":"Send a smaller request body."},"ar":{"title":"الطلب كبير جدًا","fix":"أرسل جسم طلب أصغر."}},{"code":"idempotency_key_reused","status":422,"en":{"title":"Idempotency-Key reused","fix":"A key belongs to one request. Use a new Idempotency-Key for a different body."},"ar":{"title":"تكرار Idempotency-Key","fix":"المفتاح خاص بطلب واحد. استخدم Idempotency-Key جديدًا لجسم مختلف."}},{"code":"idempotency_in_progress","status":409,"en":{"title":"Same request still running","fix":"The first request with this key has not finished. Retry in a second."},"ar":{"title":"الطلب نفسه ما زال قيد التنفيذ","fix":"الطلب الأول بهذا المفتاح لم ينتهِ بعد. أعد المحاولة بعد ثانية."}},{"code":"window_closed","status":422,"en":{"title":"24-hour window closed","fix":"WhatsApp only delivers free-form messages within 24 hours of the customer's last message. Send an approved template instead; it reopens the conversation when they reply."},"ar":{"title":"نافذة الـ24 ساعة مغلقة","fix":"لا يسلّم واتساب الرسائل الحرة إلا خلال 24 ساعة من آخر رسالة للعميل. أرسل قالبًا معتمدًا بدلًا منها، وتُفتح المحادثة من جديد عندما يرد العميل."}},{"code":"template_not_found","status":422,"en":{"title":"Template not found","fix":"Check the template name and language, or use its `tpl_…` id."},"ar":{"title":"القالب غير موجود","fix":"راجع اسم القالب ولغته، أو استخدم معرّفه `tpl_…`."}},{"code":"template_not_approved","status":422,"en":{"title":"Template not approved","fix":"Only templates WhatsApp approved can be sent. Wait for `template.status_changed`, or fix the rejection in Templates."},"ar":{"title":"القالب غير معتمد","fix":"لا يُرسل إلا ما اعتمده واتساب من قوالب. انتظر اعتماده، أو أصلح سبب الرفض من صفحة القوالب."}},{"code":"template_variables_mismatch","status":422,"en":{"title":"Wrong template variables","fix":"Send exactly one non-empty value per {{n}} in `template.variables.body`, in order."},"ar":{"title":"متغيرات القالب غير مطابقة","fix":"أرسل قيمة واحدة غير فارغة لكل {{n}} في `template.variables.body` وبالترتيب."}},{"code":"recipient_not_consented","status":409,"en":{"title":"Recipient has not consented","fix":"This contact has not agreed to business messages. If you have their consent elsewhere, resend with `\"consent_confirmed\": true` (it is recorded)."},"ar":{"title":"المستلِم لم يوافق","fix":"جهة الاتصال لم توافق على رسائل الأعمال. إن كانت موافقتها لديك في مكان آخر، أعد الإرسال مع `\"consent_confirmed\": true` (تُسجَّل الموافقة)."}},{"code":"recipient_opted_out","status":422,"en":{"title":"Recipient opted out","fix":"The contact asked not to be messaged. Do not retry."},"ar":{"title":"المستلِم ألغى الاشتراك","fix":"طلبت جهة الاتصال عدم مراسلتها. لا تُعد المحاولة."}},{"code":"sender_not_configured","status":422,"en":{"title":"No sending number","fix":"Connect a WhatsApp number in Settings → Channels, or pass a valid `from`."},"ar":{"title":"لا يوجد رقم مُرسِل","fix":"اربط رقم واتساب من الإعدادات ← القنوات، أو مرّر `from` صحيحًا."}},{"code":"sender_not_sendable","status":422,"en":{"title":"Number cannot send","fix":"`reason` says why (e.g. disconnected, token expired). Fix the number in Settings → Channels."},"ar":{"title":"الرقم لا يستطيع الإرسال","fix":"يوضّح `reason` السبب (مثل انقطاع الربط أو انتهاء الرمز). أصلح الرقم من الإعدادات ← القنوات."}},{"code":"channel_error","status":422,"en":{"title":"WhatsApp rejected it","fix":"`channel_error` carries WhatsApp's own code and message. Look the code up in WhatsApp's error list."},"ar":{"title":"رفض واتساب الرسالة","fix":"يحمل `channel_error` رمز واتساب ورسالته. ابحث عن الرمز في قائمة أخطاء واتساب."}},{"code":"send_outcome_unknown","status":409,"en":{"title":"Earlier attempt may have been sent","fix":"A previous request with this Idempotency-Key got an unclear answer from WhatsApp. Check `GET /v1/messages?reference=…` before sending again."},"ar":{"title":"ربما أُرسلت المحاولة السابقة","fix":"تلقى طلب سابق بنفس Idempotency-Key ردًّا غير واضح من واتساب. تحقق عبر `GET /v1/messages?reference=…` قبل الإرسال مرة أخرى."}},{"code":"channel_not_connected","status":422,"en":{"title":"Channel not connected","fix":"Connect the channel (or reconnect it) in Settings → Channels. `param` names the field that chose the channel."},"ar":{"title":"القناة غير متصلة","fix":"اربط القناة (أو أعد ربطها) من الإعدادات ← القنوات. يوضّح `param` الحقل الذي حدّد القناة."}},{"code":"resource_exists","status":409,"en":{"title":"Already exists","fix":"Another object already uses this unique value (a phone number, an email, a name). `existing_id` names it when we can: update that one instead, or use the upsert endpoint."},"ar":{"title":"موجود مسبقًا","fix":"يوجد عنصر آخر يستخدم هذه القيمة الفريدة (رقم هاتف أو بريد أو اسم). يوضّح `existing_id` العنصر الموجود متى أمكن: حدّثه بدلًا من ذلك، أو استخدم نقطة upsert."}},{"code":"resource_in_use","status":409,"en":{"title":"Still in use","fix":"Something still depends on this object (a running campaign uses the template, a message uses the file). `details` lists what. Finish or remove those first."},"ar":{"title":"ما زال مستخدمًا","fix":"ما زال شيء يعتمد على هذا العنصر (حملة جارية تستخدم القالب، أو رسالة تستخدم الملف). يوضّح `details` ما هو. أنهِ ذلك أو احذفه أولًا."}},{"code":"state_conflict","status":409,"en":{"title":"Not allowed in the current state","fix":"The action does not fit the object's current state, e.g. resolving a conversation that is already resolved, or starting a campaign that already started. Read the object, check `state` / `status`, then decide."},"ar":{"title":"غير مسموح في الحالة الحالية","fix":"الإجراء لا يناسب حالة العنصر الحالية، مثل إغلاق محادثة مغلقة أصلًا أو بدء حملة بدأت. اقرأ العنصر وتحقق من `state` أو `status` ثم قرّر."}},{"code":"assignee_invalid","status":422,"en":{"title":"Member cannot take this conversation","fix":"Assign someone from `GET /v1/members` who can see the conversation's channel. Viewers and members without access to that number are refused."},"ar":{"title":"لا يمكن إسناد المحادثة لهذا العضو","fix":"أسند المحادثة لعضو من `GET /v1/members` يستطيع رؤية قناتها. يُرفض المشاهدون والأعضاء الذين لا يملكون صلاحية على ذلك الرقم."}},{"code":"media_invalid","status":422,"en":{"title":"File not accepted","fix":"WhatsApp limits each media type: images JPEG/PNG up to 5 MB, video MP4/3GPP up to 16 MB, audio up to 16 MB, documents up to 100 MB, stickers WebP up to 100 KB (500 KB animated). `message` says which rule failed."},"ar":{"title":"الملف غير مقبول","fix":"يضع واتساب حدودًا لكل نوع وسائط: الصور JPEG/PNG حتى 5 ميجابايت، الفيديو MP4/3GPP حتى 16 ميجابايت، الصوت حتى 16 ميجابايت، المستندات حتى 100 ميجابايت، الملصقات WebP حتى 100 كيلوبايت (500 للمتحركة). يوضّح `message` القاعدة التي لم تتحقق."}},{"code":"flow_not_triggerable","status":422,"en":{"title":"Flow cannot be started","fix":"Only a published flow whose trigger is \"API / webhook\" can be started through the API. Publish it, or change its trigger in the flow builder."},"ar":{"title":"لا يمكن تشغيل التدفق","fix":"لا يمكن تشغيل تدفق عبر الواجهة إلا إذا كان منشورًا ومشغّله \"API / ويب هوك\". انشره أو غيّر مشغّله من منشئ التدفقات."}},{"code":"webhook_url_invalid","status":422,"en":{"title":"Webhook URL not allowed","fix":"Use a public https:// URL. Private, local and cloud-metadata addresses are refused."},"ar":{"title":"رابط الويب هوك غير مقبول","fix":"استخدم رابط https:// عامًا. العناوين الخاصة والمحلية وعناوين بيانات السحابة مرفوضة."}},{"code":"webhook_endpoint_limit","status":422,"en":{"title":"Too many endpoints","fix":"Delete an endpoint you no longer use (10 per workspace)."},"ar":{"title":"نقاط استقبال كثيرة","fix":"احذف نقطة لم تعد تستخدمها (10 لكل مساحة عمل)."}},{"code":"rate_limited","status":429,"en":{"title":"Too many requests","fix":"Wait `Retry-After` seconds. Pace requests using the `RateLimit-*` headers on every response."},"ar":{"title":"طلبات كثيرة","fix":"انتظر عدد ثواني `Retry-After`. نظّم طلباتك بالاعتماد على ترويسات `RateLimit-*` في كل استجابة."}},{"code":"internal_error","status":500,"en":{"title":"Server error","fix":"Retry with the same Idempotency-Key. If it persists, contact support with the `request_id`."},"ar":{"title":"خطأ في الخادم","fix":"أعد المحاولة بنفس Idempotency-Key. إن استمر الخطأ تواصل مع الدعم واذكر `request_id`."}},{"code":"platform_paused","status":503,"en":{"title":"Sending paused","fix":"Outbound messaging is paused platform-wide for maintenance or an incident. Retry later."},"ar":{"title":"الإرسال متوقف مؤقتًا","fix":"الإرسال متوقف على مستوى المنصة لصيانة أو حادث. أعد المحاولة لاحقًا."}},{"code":"service_unavailable","status":503,"en":{"title":"Temporarily unavailable","fix":"Retry with backoff."},"ar":{"title":"غير متاح مؤقتًا","fix":"أعد المحاولة مع زيادة فترة الانتظار تدريجيًا."}}]}