Skip to content

Campaigns

View as Markdown

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.

JSON
{
  "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_at is a local time read in timezone. 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.

If some recipients opted out of business messages, the answer is recipient_not_consented with the counts:

JSON
{ "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 live stats: sent, delivered, read, failed, replied and the rates.
  • GET /campaigns/{id}/messages lists each recipient's message with its status, and WhatsApp's reason for a failure.
  • Events: campaign.started, campaign.completed, and message.* for each recipient (ids start with cmsg_).

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

gethttps://api.saei.automize.sa/v1/campaigns
  • Scope: campaigns:read
  • Live keys only

Query parameters

  • limitintegeroptional

    How many objects to return, 1 to 100.

  • cursorstringoptional

    The next_cursor from the previous page.

  • statusstringoptional

    One ofdraftscheduledin_progresspausedcompletedfailedcancelled

Response fields200
  • object"list"required
  • dataarray<Campaign>required
    Child fields (14)
    • idstringrequired
    • object"campaign"required
    • namestringrequired
    • descriptionstring | nulloptional
    • statusstringrequired

      draft until started; scheduled waits for scheduled_at; paused is held (see hold_reason): fix the cause, then POST /v1/campaigns/{id}/resume.

      One ofdraftscheduledin_progresspausedcompletedfailedcancelled

    • hold_reasonstring | nulloptional
    • templateobject | nulloptional
      Child fields (3)
      • idstringoptional
      • namestringoptional
      • languagestring | nulloptional
    • number_idstring | nulloptional
    • scheduled_atstring | nulloptional
    • timezonestring | nulloptional
    • statsobjectrequired

      Recipient counts. GET /v1/campaigns/{id} adds pending, replied and the rates.

      Child fields (10)
      • recipientsintegeroptional
      • pendingintegeroptional
      • sentintegeroptional
      • deliveredintegeroptional
      • readintegeroptional
      • failedintegeroptional
      • repliedintegeroptional
      • delivery_ratenumber | nulloptional
      • read_ratenumber | nulloptional
      • reply_ratenumber | nulloptional
    • estimated_costobject | nulloptional

      What WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.

      Child fields (6)
      • currencystringoptional
      • totalnumberoptional
      • total_usdnumberoptional
      • recipients_pricedintegeroptional
      • recipients_freeintegeroptional
      • recipients_unpricedintegeroptional
    • created_atstring | nulloptional
    • updated_atstring | nulloptional
  • has_morebooleanrequired
  • next_cursorstring | nullrequired
Errors this can return3
Try it
curl -X GET https://api.saei.automize.sa/v1/campaigns \
  -H "Authorization: Bearer $API_KEY"
Response

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

posthttps://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), or all_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_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).

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-Keystringoptional

    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.

Request body

  • namestringrequired
  • descriptionstringoptional
  • templateobjectrequired

    {"id": "tpl_…"}, or {"name": …, "language": …}. Must be approved.

    Child fields (3)
    • idstringoptional
    • namestringoptional
    • languagestringoptional
  • number_idstringoptional

    The sending number. Required when the workspace has more than one.

  • audienceobjectrequired
    Child fields (3)
    • contactsarray<string>optional
    • tagsarray<string>optional
    • all_contactsbooleanoptional
  • variablesobjectoptional

    The template's variables (as in POST /v1/messages), with per-recipient placeholders such as {{first_name}}.

  • scheduled_atstringoptional

    A future local date-time, read in timezone. Leave out to send at start.

  • timezonestringoptional
  • link_trackingbooleanoptional

    Count clicks on the template's URL buttons.

  • consent_confirmedbooleanoptional
Response fields201
  • idstringrequired
  • object"campaign"required
  • namestringrequired
  • descriptionstring | nulloptional
  • statusstringrequired

    draft until started; scheduled waits for scheduled_at; paused is held (see hold_reason): fix the cause, then POST /v1/campaigns/{id}/resume.

    One ofdraftscheduledin_progresspausedcompletedfailedcancelled

  • hold_reasonstring | nulloptional
  • templateobject | nulloptional
    Child fields (3)
    • idstringoptional
    • namestringoptional
    • languagestring | nulloptional
  • number_idstring | nulloptional
  • scheduled_atstring | nulloptional
  • timezonestring | nulloptional
  • statsobjectrequired

    Recipient counts. GET /v1/campaigns/{id} adds pending, replied and the rates.

    Child fields (10)
    • recipientsintegeroptional
    • pendingintegeroptional
    • sentintegeroptional
    • deliveredintegeroptional
    • readintegeroptional
    • failedintegeroptional
    • repliedintegeroptional
    • delivery_ratenumber | nulloptional
    • read_ratenumber | nulloptional
    • reply_ratenumber | nulloptional
  • estimated_costobject | nulloptional

    What WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.

    Child fields (6)
    • currencystringoptional
    • totalnumberoptional
    • total_usdnumberoptional
    • recipients_pricedintegeroptional
    • recipients_freeintegeroptional
    • recipients_unpricedintegeroptional
  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return10
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"
}'
Response

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

gethttps://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

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • object"campaign"required
  • namestringrequired
  • descriptionstring | nulloptional
  • statusstringrequired

    draft until started; scheduled waits for scheduled_at; paused is held (see hold_reason): fix the cause, then POST /v1/campaigns/{id}/resume.

    One ofdraftscheduledin_progresspausedcompletedfailedcancelled

  • hold_reasonstring | nulloptional
  • templateobject | nulloptional
    Child fields (3)
    • idstringoptional
    • namestringoptional
    • languagestring | nulloptional
  • number_idstring | nulloptional
  • scheduled_atstring | nulloptional
  • timezonestring | nulloptional
  • statsobjectrequired

    Recipient counts. GET /v1/campaigns/{id} adds pending, replied and the rates.

    Child fields (10)
    • recipientsintegeroptional
    • pendingintegeroptional
    • sentintegeroptional
    • deliveredintegeroptional
    • readintegeroptional
    • failedintegeroptional
    • repliedintegeroptional
    • delivery_ratenumber | nulloptional
    • read_ratenumber | nulloptional
    • reply_ratenumber | nulloptional
  • estimated_costobject | nulloptional

    What WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.

    Child fields (6)
    • currencystringoptional
    • totalnumberoptional
    • total_usdnumberoptional
    • recipients_pricedintegeroptional
    • recipients_freeintegeroptional
    • recipients_unpricedintegeroptional
  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return3
Try it
curl -X GET https://api.saei.automize.sa/v1/campaigns/cmp_64 \
  -H "Authorization: Bearer $API_KEY"
Response

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

posthttps://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

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • object"campaign"required
  • namestringrequired
  • descriptionstring | nulloptional
  • statusstringrequired

    draft until started; scheduled waits for scheduled_at; paused is held (see hold_reason): fix the cause, then POST /v1/campaigns/{id}/resume.

    One ofdraftscheduledin_progresspausedcompletedfailedcancelled

  • hold_reasonstring | nulloptional
  • templateobject | nulloptional
    Child fields (3)
    • idstringoptional
    • namestringoptional
    • languagestring | nulloptional
  • number_idstring | nulloptional
  • scheduled_atstring | nulloptional
  • timezonestring | nulloptional
  • statsobjectrequired

    Recipient counts. GET /v1/campaigns/{id} adds pending, replied and the rates.

    Child fields (10)
    • recipientsintegeroptional
    • pendingintegeroptional
    • sentintegeroptional
    • deliveredintegeroptional
    • readintegeroptional
    • failedintegeroptional
    • repliedintegeroptional
    • delivery_ratenumber | nulloptional
    • read_ratenumber | nulloptional
    • reply_ratenumber | nulloptional
  • estimated_costobject | nulloptional

    What WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.

    Child fields (6)
    • currencystringoptional
    • totalnumberoptional
    • total_usdnumberoptional
    • recipients_pricedintegeroptional
    • recipients_freeintegeroptional
    • recipients_unpricedintegeroptional
  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return4
Try it
curl -X POST https://api.saei.automize.sa/v1/campaigns/cmp_64/cancel \
  -H "Authorization: Bearer $API_KEY"
Response

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

gethttps://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

  • idstringrequired

    The object's id.

Query parameters

  • limitintegeroptional

    How many objects to return, 1 to 100.

  • cursorstringoptional

    The next_cursor from the previous page.

  • statusstringoptional

    One ofpendingsentdeliveredreadfailedcancelled

Response fields200
  • object"list"required
  • dataarray<Message>required
    Child fields (28)
    • idstringrequired

      Unique id. Opaque: store it as a string of up to 64 characters.

    • object"message"required
    • livemodebooleanrequired
    • directionstringrequired

      outbound for messages you send, inbound for customer messages.

      One ofoutboundinbound

    • channelstringrequired

      One ofwhatsappinstagrammessenger

    • fromstring | nulloptional

      Sender, in E.164 for WhatsApp.

    • tostring | nulloptional

      Recipient, in E.164 for WhatsApp.

    • typestringrequired

      What kind of content the message carries.

    • textobjectoptional
      Child fields (1)
      • bodystringoptional
    • templateobjectoptional
      Child fields (4)
      • namestringoptional
      • languagestringoptional
      • variablesobjectoptional
      • bodystringoptional
    • imageobjectoptional

      Media messages carry link (or media_id), caption, filename and mime_type when known.

    • videoobjectoptional
    • audioobjectoptional
    • documentobjectoptional
    • stickerobjectoptional
    • locationobjectoptional
    • contactsarrayoptional
    • interactiveobjectoptional

      What you sent (type, body, buttons…), or for a customer's tap, reply: {id, title}.

    • reactionobjectoptional
    • statusstringrequired

      accepted → sent → delivered → read, or failed. Customer messages are received. Status changes arrive as webhook events.

      One ofacceptedsentdeliveredreadfailedreceived

    • errorobject | nulloptional

      Why delivery failed, when status is failed.

      Child fields (3)
      • codestring | nulloptional
      • titlestring | nulloptional
      • messagestring | nulloptional
    • referencestring | nulloptional

      Your own reference, echoed back from the send request and in every event.

    • conversation_idstring | nulloptional
    • provider_message_idstring | nulloptional

      WhatsApp's own message id (wamid).

    • contactobject | nulloptional
      Child fields (1)
      • namestring | nulloptional
    • contextobject | nulloptional

      For a reply, the message being replied to.

      Child fields (1)
      • provider_message_idstringoptional
    • created_atstring | nullrequired
    • updated_atstring | nulloptional
  • has_morebooleanrequired
  • next_cursorstring | nullrequired
Errors this can return4
Try it
curl -X GET https://api.saei.automize.sa/v1/campaigns/cmp_64/messages \
  -H "Authorization: Bearer $API_KEY"
Response

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

posthttps://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

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • object"campaign"required
  • namestringrequired
  • descriptionstring | nulloptional
  • statusstringrequired

    draft until started; scheduled waits for scheduled_at; paused is held (see hold_reason): fix the cause, then POST /v1/campaigns/{id}/resume.

    One ofdraftscheduledin_progresspausedcompletedfailedcancelled

  • hold_reasonstring | nulloptional
  • templateobject | nulloptional
    Child fields (3)
    • idstringoptional
    • namestringoptional
    • languagestring | nulloptional
  • number_idstring | nulloptional
  • scheduled_atstring | nulloptional
  • timezonestring | nulloptional
  • statsobjectrequired

    Recipient counts. GET /v1/campaigns/{id} adds pending, replied and the rates.

    Child fields (10)
    • recipientsintegeroptional
    • pendingintegeroptional
    • sentintegeroptional
    • deliveredintegeroptional
    • readintegeroptional
    • failedintegeroptional
    • repliedintegeroptional
    • delivery_ratenumber | nulloptional
    • read_ratenumber | nulloptional
    • reply_ratenumber | nulloptional
  • estimated_costobject | nulloptional

    What WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.

    Child fields (6)
    • currencystringoptional
    • totalnumberoptional
    • total_usdnumberoptional
    • recipients_pricedintegeroptional
    • recipients_freeintegeroptional
    • recipients_unpricedintegeroptional
  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return5
Try it
curl -X POST https://api.saei.automize.sa/v1/campaigns/cmp_64/resume \
  -H "Authorization: Bearer $API_KEY"
Response

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

posthttps://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

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • object"campaign"required
  • namestringrequired
  • descriptionstring | nulloptional
  • statusstringrequired

    draft until started; scheduled waits for scheduled_at; paused is held (see hold_reason): fix the cause, then POST /v1/campaigns/{id}/resume.

    One ofdraftscheduledin_progresspausedcompletedfailedcancelled

  • hold_reasonstring | nulloptional
  • templateobject | nulloptional
    Child fields (3)
    • idstringoptional
    • namestringoptional
    • languagestring | nulloptional
  • number_idstring | nulloptional
  • scheduled_atstring | nulloptional
  • timezonestring | nulloptional
  • statsobjectrequired

    Recipient counts. GET /v1/campaigns/{id} adds pending, replied and the rates.

    Child fields (10)
    • recipientsintegeroptional
    • pendingintegeroptional
    • sentintegeroptional
    • deliveredintegeroptional
    • readintegeroptional
    • failedintegeroptional
    • repliedintegeroptional
    • delivery_ratenumber | nulloptional
    • read_ratenumber | nulloptional
    • reply_ratenumber | nulloptional
  • estimated_costobject | nulloptional

    What WhatsApp will charge, in SAR (and USD), at the current rate card. Fixed at start; an estimate on a draft.

    Child fields (6)
    • currencystringoptional
    • totalnumberoptional
    • total_usdnumberoptional
    • recipients_pricedintegeroptional
    • recipients_freeintegeroptional
    • recipients_unpricedintegeroptional
  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return8
Try it
curl -X POST https://api.saei.automize.sa/v1/campaigns/cmp_64/start \
  -H "Authorization: Bearer $API_KEY"
Response

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"
}