Campaigns
Broadcast an approved template to an audience, and follow the results.
A campaign sends one approved template to many contacts, paced to protect your number, with its results collected for you. Use it for announcements and offers; for one message triggered by your system (an order update), send it directly with POST /messages.
How it works: Campaigns1. Create a draft · 2. Answer the consent question · 3. Check the price, then start · 4. Follow the results · Holds, resuming and cancelling
1. Create a draft#
POST /campaigns builds the recipient list and prices it. Nothing is sent yet.
{
"name": "عرض نهاية الأسبوع",
"template": { "name": "weekend_offer", "language": "ar" },
"audience": { "tags": ["عملاء VIP"] },
"variables": { "body": ["{{first_name}}", "20٪"] },
"scheduled_at": "2026-10-02T16:00:00",
"timezone": "Asia/Riyadh"
}- Audience.
contacts(ids),tags(ids or names), or"all_contacts": true. - Personal values. In
variables,{{first_name}},{{last_name}},{{phone_number}}or any custom field key is filled in for each recipient. - Schedule.
scheduled_atis a local time read intimezone. Leave it out to send as soon as you start. - Numbers. With several WhatsApp numbers, say which sends with
number_id; the template must belong to that number's account.
2. Answer the consent question#
If some recipients opted out of business messages, the answer is recipient_not_consented with the counts:
{ "error": { "code": "recipient_not_consented", "unconsented": 12, "recipients": 348, "param": "consent_confirmed", "...": "..." } }Send the request again with "consent_confirmed": false to leave them out, or true only if they agreed again. Your answer is recorded in the audit log.
3. Check the price, then start#
The draft carries estimated_cost: what WhatsApp will charge in SAR at today's rates, with how many recipients are priced, free and unpriced. When it looks right, POST /campaigns/{id}/start.
Starting runs the same checks as the portal: the number must be able to broadcast (a number Meta has limited cannot), Meta must not be blocking delivery for billing, and the plan's monthly campaigns and marketing messages must cover it (quota_exceeded otherwise).
4. Follow the results#
GET /campaigns/{id}gives livestats: sent, delivered, read, failed, replied and the rates.GET /campaigns/{id}/messageslists each recipient's message with its status, and WhatsApp's reason for a failure.- Events:
campaign.started,campaign.completed, andmessage.*for each recipient (ids start withcmsg_).
Holds, resuming and cancelling#
Sending is paced. If the number runs into a limit Meta set, the campaign is held (status: paused, hold_reason says why) and you get campaign.paused. Fix the cause, then POST /campaigns/{id}/resume: a held campaign never restarts by itself, because a number just back from a restriction should not start broadcasting unattended.
POST /campaigns/{id}/cancel stops a scheduled or sending campaign; messages already sent stay sent.
Endpoints
List campaigns
https://api.saei.automize.sa/v1/campaigns- Scope:
campaigns:read - Live keys only
Query parameters
limitintegeroptionalHow many objects to return, 1 to 100.
cursorstringoptionalThe
next_cursorfrom the previous page.statusstringoptionalOne of
draftscheduledin_progresspausedcompletedfailedcancelled
Response fields200· A page of campaigns.
object"list"requireddataarray<Campaign>requiredChild fields (14)
idstringrequiredobject"campaign"requirednamestringrequireddescriptionstring | nulloptionalstatusstringrequireddraftuntil started;scheduledwaits forscheduled_at;pausedis held (seehold_reason): fix the cause, thenPOST /v1/campaigns/{id}/resume.One of
draftscheduledin_progresspausedcompletedfailedcancelledhold_reasonstring | nulloptionaltemplateobject | nulloptionalChild fields (3)
idstringoptionalnamestringoptionallanguagestring | nulloptional
number_idstring | nulloptionalscheduled_atstring | nulloptionaltimezonestring | nulloptionalstatsobjectrequiredRecipient counts.
GET /v1/campaigns/{id}addspending,repliedand the rates.Child fields (10)
recipientsintegeroptionalpendingintegeroptionalsentintegeroptionaldeliveredintegeroptionalreadintegeroptionalfailedintegeroptionalrepliedintegeroptionaldelivery_ratenumber | nulloptionalread_ratenumber | nulloptionalreply_ratenumber | nulloptional
estimated_costobject | nulloptionalWhat WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.
Child fields (6)
currencystringoptionaltotalnumberoptionaltotal_usdnumberoptionalrecipients_pricedintegeroptionalrecipients_freeintegeroptionalrecipients_unpricedintegeroptional
created_atstring | nulloptionalupdated_atstring | nulloptional
has_morebooleanrequirednext_cursorstring | nullrequired
Errors this can return3
- 403test_mode_unsupportedNot in test mode
- 422parameter_invalidInvalid parameter
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/campaigns \
-H "Authorization: Bearer $API_KEY"A page of campaigns.
{
"object": "list",
"data": [
{
"id": "cmp_64",
"object": "campaign",
"name": "string",
"description": "string",
"status": "draft",
"hold_reason": "string",
"template": {
"id": "string",
"name": "string",
"language": "string"
},
"number_id": "string",
"scheduled_at": "2026-10-01T09:30:00Z",
"timezone": "string",
"stats": {
"recipients": 0,
"pending": 0,
"sent": 0,
"delivered": 0,
"read": 0,
"failed": 0,
"replied": 0,
"delivery_rate": 0,
"read_rate": 0,
"reply_rate": 0
},
"estimated_cost": {
"currency": "string",
"total": 0,
"total_usd": 0,
"recipients_priced": 0,
"recipients_free": 0,
"recipients_unpriced": 0
},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}
],
"has_more": false,
"next_cursor": "string"
}Create a campaign
https://api.saei.automize.sa/v1/campaigns- Scope:
campaigns:write - Live keys only
- Accepts Idempotency-Key
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.
- Audience:
contacts(ids),tags(ids or names), orall_contacts: true. - 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%"]. - Consent: if some recipients opted out of business messages, the answer is
recipient_not_consentedwith the counts. Sendconsent_confirmed: falseto skip them, ortrueonly if they agreed again (your confirmation is recorded in the audit log).
Every 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.
Headers
Idempotency-KeystringoptionalAny 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.
Request body
namestringrequireddescriptionstringoptionaltemplateobjectrequired{"id": "tpl_…"}, or{"name": …, "language": …}. Must be approved.Child fields (3)
idstringoptionalnamestringoptionallanguagestringoptional
number_idstringoptionalThe sending number. Required when the workspace has more than one.
audienceobjectrequiredChild fields (3)
contactsarray<string>optionaltagsarray<string>optionalall_contactsbooleanoptional
variablesobjectoptionalThe template's variables (as in
POST /v1/messages), with per-recipient placeholders such as{{first_name}}.scheduled_atstringoptionalA future local date-time, read in
timezone. Leave out to send at start.timezonestringoptionallink_trackingbooleanoptionalCount clicks on the template's URL buttons.
consent_confirmedbooleanoptional
Response fields201· The draft, with its price estimate.
idstringrequiredobject"campaign"requirednamestringrequireddescriptionstring | nulloptionalstatusstringrequireddraftuntil started;scheduledwaits forscheduled_at;pausedis held (seehold_reason): fix the cause, thenPOST /v1/campaigns/{id}/resume.One of
draftscheduledin_progresspausedcompletedfailedcancelledhold_reasonstring | nulloptionaltemplateobject | nulloptionalChild fields (3)
idstringoptionalnamestringoptionallanguagestring | nulloptional
number_idstring | nulloptionalscheduled_atstring | nulloptionaltimezonestring | nulloptionalstatsobjectrequiredRecipient counts.
GET /v1/campaigns/{id}addspending,repliedand the rates.Child fields (10)
recipientsintegeroptionalpendingintegeroptionalsentintegeroptionaldeliveredintegeroptionalreadintegeroptionalfailedintegeroptionalrepliedintegeroptionaldelivery_ratenumber | nulloptionalread_ratenumber | nulloptionalreply_ratenumber | nulloptional
estimated_costobject | nulloptionalWhat WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.
Child fields (6)
currencystringoptionaltotalnumberoptionaltotal_usdnumberoptionalrecipients_pricedintegeroptionalrecipients_freeintegeroptionalrecipients_unpricedintegeroptional
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return10
- 403test_mode_unsupportedNot in test mode
- 422parameter_missingMissing parameter
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
- 422template_not_foundTemplate not found
- 422template_not_approvedTemplate not approved
- 422template_variables_mismatchWrong template variables
- 409recipient_not_consentedRecipient has not consented
- 422sender_not_sendableNumber cannot send
- 429rate_limitedToo many requests
Try it
curl -X POST https://api.saei.automize.sa/v1/campaigns \
-H "Authorization: Bearer $API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"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"
}'The draft, with its price estimate.
{
"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"
}Get a campaign
https://api.saei.automize.sa/v1/campaigns/{id}- Scope:
campaigns:read - Live keys only
The campaign with live results (sent, delivered, read, failed, replied and the rates).
Path parameters
idstringrequiredThe object's id.
Response fields200· The campaign.
idstringrequiredobject"campaign"requirednamestringrequireddescriptionstring | nulloptionalstatusstringrequireddraftuntil started;scheduledwaits forscheduled_at;pausedis held (seehold_reason): fix the cause, thenPOST /v1/campaigns/{id}/resume.One of
draftscheduledin_progresspausedcompletedfailedcancelledhold_reasonstring | nulloptionaltemplateobject | nulloptionalChild fields (3)
idstringoptionalnamestringoptionallanguagestring | nulloptional
number_idstring | nulloptionalscheduled_atstring | nulloptionaltimezonestring | nulloptionalstatsobjectrequiredRecipient counts.
GET /v1/campaigns/{id}addspending,repliedand the rates.Child fields (10)
recipientsintegeroptionalpendingintegeroptionalsentintegeroptionaldeliveredintegeroptionalreadintegeroptionalfailedintegeroptionalrepliedintegeroptionaldelivery_ratenumber | nulloptionalread_ratenumber | nulloptionalreply_ratenumber | nulloptional
estimated_costobject | nulloptionalWhat WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.
Child fields (6)
currencystringoptionaltotalnumberoptionaltotal_usdnumberoptionalrecipients_pricedintegeroptionalrecipients_freeintegeroptionalrecipients_unpricedintegeroptional
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return3
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/campaigns/cmp_64 \
-H "Authorization: Bearer $API_KEY"The campaign.
{
"id": "cmp_64",
"object": "campaign",
"name": "string",
"description": "string",
"status": "draft",
"hold_reason": "string",
"template": {
"id": "string",
"name": "string",
"language": "string"
},
"number_id": "string",
"scheduled_at": "2026-10-01T09:30:00Z",
"timezone": "string",
"stats": {
"recipients": 0,
"pending": 0,
"sent": 0,
"delivered": 0,
"read": 0,
"failed": 0,
"replied": 0,
"delivery_rate": 0,
"read_rate": 0,
"reply_rate": 0
},
"estimated_cost": {
"currency": "string",
"total": 0,
"total_usd": 0,
"recipients_priced": 0,
"recipients_free": 0,
"recipients_unpriced": 0
},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}Cancel a campaign
https://api.saei.automize.sa/v1/campaigns/{id}/cancel- Scope:
campaigns:write - Live keys only
Stops a scheduled or sending campaign. Messages already sent stay sent; the rest are cancelled.
Path parameters
idstringrequiredThe object's id.
Response fields200· Cancelled.
idstringrequiredobject"campaign"requirednamestringrequireddescriptionstring | nulloptionalstatusstringrequireddraftuntil started;scheduledwaits forscheduled_at;pausedis held (seehold_reason): fix the cause, thenPOST /v1/campaigns/{id}/resume.One of
draftscheduledin_progresspausedcompletedfailedcancelledhold_reasonstring | nulloptionaltemplateobject | nulloptionalChild fields (3)
idstringoptionalnamestringoptionallanguagestring | nulloptional
number_idstring | nulloptionalscheduled_atstring | nulloptionaltimezonestring | nulloptionalstatsobjectrequiredRecipient counts.
GET /v1/campaigns/{id}addspending,repliedand the rates.Child fields (10)
recipientsintegeroptionalpendingintegeroptionalsentintegeroptionaldeliveredintegeroptionalreadintegeroptionalfailedintegeroptionalrepliedintegeroptionaldelivery_ratenumber | nulloptionalread_ratenumber | nulloptionalreply_ratenumber | nulloptional
estimated_costobject | nulloptionalWhat WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.
Child fields (6)
currencystringoptionaltotalnumberoptionaltotal_usdnumberoptionalrecipients_pricedintegeroptionalrecipients_freeintegeroptionalrecipients_unpricedintegeroptional
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return4
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 409state_conflictNot allowed in the current state
- 429rate_limitedToo many requests
Try it
curl -X POST https://api.saei.automize.sa/v1/campaigns/cmp_64/cancel \
-H "Authorization: Bearer $API_KEY"Cancelled.
{
"id": "cmp_64",
"object": "campaign",
"name": "string",
"description": "string",
"status": "draft",
"hold_reason": "string",
"template": {
"id": "string",
"name": "string",
"language": "string"
},
"number_id": "string",
"scheduled_at": "2026-10-01T09:30:00Z",
"timezone": "string",
"stats": {
"recipients": 0,
"pending": 0,
"sent": 0,
"delivered": 0,
"read": 0,
"failed": 0,
"replied": 0,
"delivery_rate": 0,
"read_rate": 0,
"reply_rate": 0
},
"estimated_cost": {
"currency": "string",
"total": 0,
"total_usd": 0,
"recipients_priced": 0,
"recipients_free": 0,
"recipients_unpriced": 0
},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}List a campaign's recipients
https://api.saei.automize.sa/v1/campaigns/{id}/messages- Scope:
campaigns:read - Live keys only
One message per recipient (cmsg_…), with its delivery status and, for a failure, WhatsApp's reason. Their status changes also arrive as message.* events.
Path parameters
idstringrequiredThe object's id.
Query parameters
limitintegeroptionalHow many objects to return, 1 to 100.
cursorstringoptionalThe
next_cursorfrom the previous page.statusstringoptionalOne of
pendingsentdeliveredreadfailedcancelled
Response fields200· A page of recipient messages.
object"list"requireddataarray<Message>requiredChild fields (28)
idstringrequiredUnique id. Opaque: store it as a string of up to 64 characters.
object"message"requiredlivemodebooleanrequireddirectionstringrequiredoutboundfor messages you send,inboundfor customer messages.One of
outboundinboundchannelstringrequiredOne of
whatsappinstagrammessengerfromstring | nulloptionalSender, in E.164 for WhatsApp.
tostring | nulloptionalRecipient, in E.164 for WhatsApp.
typestringrequiredWhat kind of content the message carries.
textobjectoptionalChild fields (1)
bodystringoptional
templateobjectoptionalChild fields (4)
namestringoptionallanguagestringoptionalvariablesobjectoptionalbodystringoptional
imageobjectoptionalMedia messages carry
link(ormedia_id),caption,filenameandmime_typewhen known.videoobjectoptionalaudioobjectoptionaldocumentobjectoptionalstickerobjectoptionallocationobjectoptionalcontactsarrayoptionalinteractiveobjectoptionalWhat you sent (
type,body,buttons…), or for a customer's tap,reply: {id, title}.reactionobjectoptionalstatusstringrequiredaccepted→sent→delivered→read, orfailed. Customer messages arereceived. Status changes arrive as webhook events.One of
acceptedsentdeliveredreadfailedreceivederrorobject | nulloptionalWhy delivery failed, when
statusisfailed.Child fields (3)
codestring | nulloptionaltitlestring | nulloptionalmessagestring | nulloptional
referencestring | nulloptionalYour own reference, echoed back from the send request and in every event.
conversation_idstring | nulloptionalprovider_message_idstring | nulloptionalWhatsApp's own message id (wamid).
contactobject | nulloptionalChild fields (1)
namestring | nulloptional
contextobject | nulloptionalFor a reply, the message being replied to.
Child fields (1)
provider_message_idstringoptional
created_atstring | nullrequiredupdated_atstring | nulloptional
has_morebooleanrequirednext_cursorstring | nullrequired
Errors this can return4
- 403test_mode_unsupportedNot in test mode
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/campaigns/cmp_64/messages \
-H "Authorization: Bearer $API_KEY"A page of recipient messages.
{
"object": "list",
"data": [
{
"id": "msg_48213",
"object": "message",
"livemode": false,
"direction": "outbound",
"channel": "whatsapp",
"from": "+966112345678",
"to": "+966501234567",
"type": "text",
"text": {
"body": "string"
},
"template": {
"name": "string",
"language": "string",
"variables": {},
"body": "string"
},
"image": {},
"video": {},
"audio": {},
"document": {},
"sticker": {},
"location": {},
"contacts": [],
"interactive": {},
"reaction": {},
"status": "accepted",
"error": {
"code": "string",
"title": "string",
"message": "string"
},
"reference": "string",
"conversation_id": "string",
"provider_message_id": "string",
"contact": {
"name": "string"
},
"context": {
"provider_message_id": "string"
},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}
],
"has_more": false,
"next_cursor": "string"
}Resume a paused campaign
https://api.saei.automize.sa/v1/campaigns/{id}/resume- Scope:
campaigns:write - Live keys only
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.
Path parameters
idstringrequiredThe object's id.
Response fields200· Sending again.
idstringrequiredobject"campaign"requirednamestringrequireddescriptionstring | nulloptionalstatusstringrequireddraftuntil started;scheduledwaits forscheduled_at;pausedis held (seehold_reason): fix the cause, thenPOST /v1/campaigns/{id}/resume.One of
draftscheduledin_progresspausedcompletedfailedcancelledhold_reasonstring | nulloptionaltemplateobject | nulloptionalChild fields (3)
idstringoptionalnamestringoptionallanguagestring | nulloptional
number_idstring | nulloptionalscheduled_atstring | nulloptionaltimezonestring | nulloptionalstatsobjectrequiredRecipient counts.
GET /v1/campaigns/{id}addspending,repliedand the rates.Child fields (10)
recipientsintegeroptionalpendingintegeroptionalsentintegeroptionaldeliveredintegeroptionalreadintegeroptionalfailedintegeroptionalrepliedintegeroptionaldelivery_ratenumber | nulloptionalread_ratenumber | nulloptionalreply_ratenumber | nulloptional
estimated_costobject | nulloptionalWhat WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.
Child fields (6)
currencystringoptionaltotalnumberoptionaltotal_usdnumberoptionalrecipients_pricedintegeroptionalrecipients_freeintegeroptionalrecipients_unpricedintegeroptional
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return5
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 422sender_not_sendableNumber cannot send
- 409state_conflictNot allowed in the current state
- 429rate_limitedToo many requests
Try it
curl -X POST https://api.saei.automize.sa/v1/campaigns/cmp_64/resume \
-H "Authorization: Bearer $API_KEY"Sending again.
{
"id": "cmp_64",
"object": "campaign",
"name": "string",
"description": "string",
"status": "draft",
"hold_reason": "string",
"template": {
"id": "string",
"name": "string",
"language": "string"
},
"number_id": "string",
"scheduled_at": "2026-10-01T09:30:00Z",
"timezone": "string",
"stats": {
"recipients": 0,
"pending": 0,
"sent": 0,
"delivered": 0,
"read": 0,
"failed": 0,
"replied": 0,
"delivery_rate": 0,
"read_rate": 0,
"reply_rate": 0
},
"estimated_cost": {
"currency": "string",
"total": 0,
"total_usd": 0,
"recipients_priced": 0,
"recipients_free": 0,
"recipients_unpriced": 0
},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}Start a campaign
https://api.saei.automize.sa/v1/campaigns/{id}/start- Scope:
campaigns:write - Live keys only
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}.
Path parameters
idstringrequiredThe object's id.
Response fields200· Started (`in_progress`) or scheduled (`scheduled`).
idstringrequiredobject"campaign"requirednamestringrequireddescriptionstring | nulloptionalstatusstringrequireddraftuntil started;scheduledwaits forscheduled_at;pausedis held (seehold_reason): fix the cause, thenPOST /v1/campaigns/{id}/resume.One of
draftscheduledin_progresspausedcompletedfailedcancelledhold_reasonstring | nulloptionaltemplateobject | nulloptionalChild fields (3)
idstringoptionalnamestringoptionallanguagestring | nulloptional
number_idstring | nulloptionalscheduled_atstring | nulloptionaltimezonestring | nulloptionalstatsobjectrequiredRecipient counts.
GET /v1/campaigns/{id}addspending,repliedand the rates.Child fields (10)
recipientsintegeroptionalpendingintegeroptionalsentintegeroptionaldeliveredintegeroptionalreadintegeroptionalfailedintegeroptionalrepliedintegeroptionaldelivery_ratenumber | nulloptionalread_ratenumber | nulloptionalreply_ratenumber | nulloptional
estimated_costobject | nulloptionalWhat WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.
Child fields (6)
currencystringoptionaltotalnumberoptionaltotal_usdnumberoptionalrecipients_pricedintegeroptionalrecipients_freeintegeroptionalrecipients_unpricedintegeroptional
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return8
- 402quota_exceededAllowance used up
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 422sender_not_configuredNo sending number
- 422sender_not_sendableNumber cannot send
- 422channel_errorWhatsApp rejected it
- 409state_conflictNot allowed in the current state
- 429rate_limitedToo many requests
Try it
curl -X POST https://api.saei.automize.sa/v1/campaigns/cmp_64/start \
-H "Authorization: Bearer $API_KEY"Started (`in_progress`) or scheduled (`scheduled`).
{
"id": "cmp_64",
"object": "campaign",
"name": "string",
"description": "string",
"status": "draft",
"hold_reason": "string",
"template": {
"id": "string",
"name": "string",
"language": "string"
},
"number_id": "string",
"scheduled_at": "2026-10-01T09:30:00Z",
"timezone": "string",
"stats": {
"recipients": 0,
"pending": 0,
"sent": 0,
"delivered": 0,
"read": 0,
"failed": 0,
"replied": 0,
"delivery_rate": 0,
"read_rate": 0,
"reply_rate": 0
},
"estimated_cost": {
"currency": "string",
"total": 0,
"total_usd": 0,
"recipients_priced": 0,
"recipients_free": 0,
"recipients_unpriced": 0
},
"created_at": "2026-10-01T09:30:00Z",
"updated_at": "2026-10-01T09:30:00Z"
}