Skip to content

Contacts

View as Markdown

Keep contacts, tags and custom fields in step with your systems.

Keep this workspace's contacts in step with your CRM, store or ERP: push changes as they happen with upsert, and hear about changes made here through contact.* events.

How it works: Syncing contactsOne phone, one contact · Push changes with upsert · Tags and custom fields · Consent · Hear about changes made here · Catch up after downtime · Delete a contact

One phone, one contact#

A contact is identified by its phone number. Send it in any common format (+966 50 123 4567, 00966501234567, 0501234567); it is stored and returned in E.164 (+966501234567). Creating a second contact with the same number is refused with resource_exists, and existing_id names the one that exists.

Push changes with upsert#

POST /contacts/upsert finds the contact by phone and changes only the fields you send, or creates it. It answers 201 when it created and 200 when it updated, so one call covers "new customer" and "customer changed":

JSON
{
  "phone": "0501234567",
  "first_name": "سارة",
  "email": "sara@example.com",
  "language": "ar",
  "tags": ["عملاء VIP"],
  "fields": { "loyalty_points": 180, "branch": "riyadh" }
}

Send an Idempotency-Key too: a retried upsert then never applies twice.

Tags and custom fields#

  • Tags take ids (tag_…) or names; a name that does not exist yet is created. In an upsert or a PATCH, tags replaces the contact's tags. To add without removing, use POST /contacts/{id}/tags; to remove one, DELETE /contacts/{id}/tags/{tag}.
  • Custom fields go in fields, by the keys from GET /contact_fields. Values are checked against the field: a number, a date as YYYY-MM-DD, or one of a list's options. An empty value clears the field. Values come back as strings.

opted_in says whether the contact accepts business messages.

  • Opting out. PATCH with "opted_in": false works like the customer sending STOP: campaign messages queued for them are cancelled, and templates to them need consent_confirmed from then on.
  • Opting back in needs a record of how they agreed: "opted_in": true, "consent": {"source": "paper_form"}. Sources are website_form, paper_form, existing_customer, whatsapp_conversation, or other with a note.
  • Customers can also opt out and in themselves by message (see Arabic & Saudi specifics). You hear about it through contact.opted_out and contact.opted_in.

Hear about changes made here#

Subscribe an endpoint to contact.* and your system stays current with changes from the portal, imports, flows and the API:

EventWhen
contact.createdA contact was added
contact.updatedDetails, tags or fields changed
contact.opted_out / contact.opted_inConsent changed
contact.deletedThe contact was deleted: delete your copy

Contact events wait a few seconds so they carry the finished contact (a new contact's tags and fields are written just after it is created), and several quick changes arrive as one contact.updated. data.object is always the whole contact, so apply it as a snapshot rather than a diff.

Catch up after downtime#

If your receiver was down, list what changed since your last sync with GET /contacts?updated_since=2026-10-01T00:00:00Z and page through with cursor. Deletions are only reported by contact.deleted events, which keep being retried on the usual schedule and can be replayed from the delivery log.

Delete a contact#

DELETE /contacts/{id} removes the contact, its tags and field values, and cancels campaign messages still queued for them: the answer to a request to be forgotten. Their conversation history stays in the inbox.

Endpoints

List custom contact fields

gethttps://api.saei.automize.sa/v1/contact_fields
  • Scope: contacts:read
  • Works in test mode

The custom fields your contacts carry (created in Contacts → Fields). Use each key in a contact's fields.

Response fields200
  • object"list"required
  • dataarray<ContactField>required
    Child fields (7)
    • idstringrequired
    • object"contact_field"required
    • keystringrequired
    • labelstringrequired
    • typestringrequired

      One oftextnumberdateselect

    • optionsarray | nulloptional

      The allowed values of a select field.

    • requiredbooleanrequired
  • has_morebooleanrequired
  • next_cursorstring | nullrequired
Errors this can return1
Try it
curl -X GET https://api.saei.automize.sa/v1/contact_fields \
  -H "Authorization: Bearer $API_KEY"
Response

Every custom field, in the portal's order.

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

List contacts

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

Your WhatsApp contacts, newest first. Find one person with phone (any format: +966 50 123 4567, 0501234567…), or sync changes with updated_since.

Query parameters

  • limitintegeroptional

    How many objects to return, 1 to 100.

  • cursorstringoptional

    The next_cursor from the previous page.

  • phonestringoptional
  • emailstringoptional
  • tagstringoptional

    A tag id (tag_…) or name.

  • opted_inbooleanoptional
  • updated_sincestringoptional

    Only contacts changed at or after this time (ISO 8601).

Response fields200
  • object"list"required
  • dataarray<Contact>required
    Child fields (20)
    • idstringrequired
    • object"contact"required
    • phonestring | nullrequired
    • emailstring | nulloptional
    • first_namestring | nulloptional
    • last_namestring | nulloptional
    • languagestring | nulloptional

      The language they prefer, e.g. ar or en.

    • countrystring | nulloptional
    • citystring | nulloptional
    • genderstring | nulloptional
    • birth_datestring | nulloptional
    • notesstring | nulloptional
    • opted_inbooleanrequired

      false once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need consent_confirmed.

    • consentobject | nulloptional

      How and when they agreed to business messages, when recorded.

      Child fields (3)
      • sourcestringoptional
      • notestringoptional
      • captured_atstringoptional
    • opted_out_atstring | nulloptional
    • bot_enabledbooleanoptional

      Whether automated replies (flows, AI bots) answer them.

    • tagsarray<object>required
      Child fields (2)
      • idstringoptional
      • namestringoptional
    • fieldsobjectrequired

      Custom field values by key. Values are strings.

    • 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/contacts \
  -H "Authorization: Bearer $API_KEY"
Response

A page of contacts.

{
  "object": "list",
  "data": [
    {
      "id": "ct_1052",
      "object": "contact",
      "phone": "+966501234567",
      "email": "string",
      "first_name": "string",
      "last_name": "string",
      "language": "string",
      "country": "string",
      "city": "string",
      "gender": "string",
      "birth_date": "string",
      "notes": "string",
      "opted_in": false,
      "consent": {
        "source": "string",
        "note": "string",
        "captured_at": "2026-10-01T09:30:00Z"
      },
      "opted_out_at": "2026-10-01T09:30:00Z",
      "bot_enabled": false,
      "tags": [
        {
          "id": "string",
          "name": "string"
        }
      ],
      "fields": {},
      "created_at": "2026-10-01T09:30:00Z",
      "updated_at": "2026-10-01T09:30:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": "string"
}

Create a contact

posthttps://api.saei.automize.sa/v1/contacts
  • Scope: contacts:write
  • Live keys only
  • Accepts Idempotency-Key

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.

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).

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

  • phonestringoptional

    Any format; stored as E.164. Saudi numbers written locally (0501234567) are understood.

  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional
  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional

    One ofmalefemaleotherprefer_not_to_saynull

  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • bot_enabledbooleanoptional
  • tagsarray<string>optional

    Tag ids (tag_…) or names. A name that does not exist is created.

  • fieldsobjectoptional

    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_inbooleanoptional
  • consentobjectoptional

    How they agreed: website_form, paper_form, existing_customer, whatsapp_conversation, or other with a note.

    Child fields (2)
    • sourcestringrequired

      One ofwebsite_formpaper_formexisting_customerwhatsapp_conversationother

    • notestringoptional
Response fields201
  • idstringrequired
  • object"contact"required
  • phonestring | nullrequired
  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional

    The language they prefer, e.g. ar or en.

  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional
  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • opted_inbooleanrequired

    false once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need consent_confirmed.

  • consentobject | nulloptional

    How and when they agreed to business messages, when recorded.

    Child fields (3)
    • sourcestringoptional
    • notestringoptional
    • captured_atstringoptional
  • opted_out_atstring | nulloptional
  • bot_enabledbooleanoptional

    Whether automated replies (flows, AI bots) answer them.

  • tagsarray<object>required
    Child fields (2)
    • idstringoptional
    • namestringoptional
  • fieldsobjectrequired

    Custom field values by key. Values are strings.

  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return7
Try it
curl -X POST https://api.saei.automize.sa/v1/contacts \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "phone": "+966501234567",
  "first_name": "سارة",
  "last_name": "القحطاني",
  "email": "sara@example.com",
  "language": "ar",
  "tags": [
    "عملاء VIP"
  ],
  "fields": {
    "loyalty_points": 120
  },
  "consent": {
    "source": "website_form"
  }
}'
Response

Created.

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

Create or update a contact by phone

posthttps://api.saei.automize.sa/v1/contacts/upsert
  • Scope: contacts:write
  • Live keys only
  • Accepts Idempotency-Key

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.

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

  • phonestringoptional

    Any format; stored as E.164. Saudi numbers written locally (0501234567) are understood.

  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional
  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional

    One ofmalefemaleotherprefer_not_to_saynull

  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • bot_enabledbooleanoptional
  • tagsarray<string>optional

    Tag ids (tag_…) or names. A name that does not exist is created.

  • fieldsobjectoptional

    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_inbooleanoptional
  • consentobjectoptional

    How they agreed: website_form, paper_form, existing_customer, whatsapp_conversation, or other with a note.

    Child fields (2)
    • sourcestringrequired

      One ofwebsite_formpaper_formexisting_customerwhatsapp_conversationother

    • notestringoptional
Response fields200
  • idstringrequired
  • object"contact"required
  • phonestring | nullrequired
  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional

    The language they prefer, e.g. ar or en.

  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional
  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • opted_inbooleanrequired

    false once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need consent_confirmed.

  • consentobject | nulloptional

    How and when they agreed to business messages, when recorded.

    Child fields (3)
    • sourcestringoptional
    • notestringoptional
    • captured_atstringoptional
  • opted_out_atstring | nulloptional
  • bot_enabledbooleanoptional

    Whether automated replies (flows, AI bots) answer them.

  • tagsarray<object>required
    Child fields (2)
    • idstringoptional
    • namestringoptional
  • fieldsobjectrequired

    Custom field values by key. Values are strings.

  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return7
Try it
curl -X POST https://api.saei.automize.sa/v1/contacts/upsert \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "phone": "0501234567",
  "first_name": "سارة",
  "fields": {
    "loyalty_points": 180
  }
}'
Response

Updated an existing contact.

{
  "id": "ct_1052",
  "object": "contact",
  "phone": "+966501234567",
  "email": "string",
  "first_name": "string",
  "last_name": "string",
  "language": "string",
  "country": "string",
  "city": "string",
  "gender": "string",
  "birth_date": "string",
  "notes": "string",
  "opted_in": false,
  "consent": {
    "source": "string",
    "note": "string",
    "captured_at": "2026-10-01T09:30:00Z"
  },
  "opted_out_at": "2026-10-01T09:30:00Z",
  "bot_enabled": false,
  "tags": [
    {
      "id": "string",
      "name": "string"
    }
  ],
  "fields": {},
  "created_at": "2026-10-01T09:30:00Z",
  "updated_at": "2026-10-01T09:30:00Z"
}

Get a contact

gethttps://api.saei.automize.sa/v1/contacts/{id}
  • Scope: contacts:read
  • Live keys only

Path parameters

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • object"contact"required
  • phonestring | nullrequired
  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional

    The language they prefer, e.g. ar or en.

  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional
  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • opted_inbooleanrequired

    false once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need consent_confirmed.

  • consentobject | nulloptional

    How and when they agreed to business messages, when recorded.

    Child fields (3)
    • sourcestringoptional
    • notestringoptional
    • captured_atstringoptional
  • opted_out_atstring | nulloptional
  • bot_enabledbooleanoptional

    Whether automated replies (flows, AI bots) answer them.

  • tagsarray<object>required
    Child fields (2)
    • idstringoptional
    • namestringoptional
  • fieldsobjectrequired

    Custom field values by key. Values are strings.

  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return3
Try it
curl -X GET https://api.saei.automize.sa/v1/contacts/ct_1052 \
  -H "Authorization: Bearer $API_KEY"
Response

The contact.

{
  "id": "ct_1052",
  "object": "contact",
  "phone": "+966501234567",
  "email": "string",
  "first_name": "string",
  "last_name": "string",
  "language": "string",
  "country": "string",
  "city": "string",
  "gender": "string",
  "birth_date": "string",
  "notes": "string",
  "opted_in": false,
  "consent": {
    "source": "string",
    "note": "string",
    "captured_at": "2026-10-01T09:30:00Z"
  },
  "opted_out_at": "2026-10-01T09:30:00Z",
  "bot_enabled": false,
  "tags": [
    {
      "id": "string",
      "name": "string"
    }
  ],
  "fields": {},
  "created_at": "2026-10-01T09:30:00Z",
  "updated_at": "2026-10-01T09:30:00Z"
}

Update a contact

patchhttps://api.saei.automize.sa/v1/contacts/{id}
  • Scope: contacts:write
  • Live keys only

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.

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.

Path parameters

  • idstringrequired

    The object's id.

Request body

  • phonestringoptional

    Any format; stored as E.164. Saudi numbers written locally (0501234567) are understood.

  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional
  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional

    One ofmalefemaleotherprefer_not_to_saynull

  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • bot_enabledbooleanoptional
  • tagsarray<string>optional

    Tag ids (tag_…) or names. A name that does not exist is created.

  • fieldsobjectoptional

    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_inbooleanoptional
  • consentobjectoptional

    How they agreed: website_form, paper_form, existing_customer, whatsapp_conversation, or other with a note.

    Child fields (2)
    • sourcestringrequired

      One ofwebsite_formpaper_formexisting_customerwhatsapp_conversationother

    • notestringoptional
Response fields200
  • idstringrequired
  • object"contact"required
  • phonestring | nullrequired
  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional

    The language they prefer, e.g. ar or en.

  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional
  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • opted_inbooleanrequired

    false once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need consent_confirmed.

  • consentobject | nulloptional

    How and when they agreed to business messages, when recorded.

    Child fields (3)
    • sourcestringoptional
    • notestringoptional
    • captured_atstringoptional
  • opted_out_atstring | nulloptional
  • bot_enabledbooleanoptional

    Whether automated replies (flows, AI bots) answer them.

  • tagsarray<object>required
    Child fields (2)
    • idstringoptional
    • namestringoptional
  • fieldsobjectrequired

    Custom field values by key. Values are strings.

  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return6
Try it
Example
curl -X PATCH https://api.saei.automize.sa/v1/contacts/ct_1052 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "city": "جدة",
  "fields": {
    "loyalty_points": 200
  }
}'
Response

The updated contact.

{
  "id": "ct_1052",
  "object": "contact",
  "phone": "+966501234567",
  "email": "string",
  "first_name": "string",
  "last_name": "string",
  "language": "string",
  "country": "string",
  "city": "string",
  "gender": "string",
  "birth_date": "string",
  "notes": "string",
  "opted_in": false,
  "consent": {
    "source": "string",
    "note": "string",
    "captured_at": "2026-10-01T09:30:00Z"
  },
  "opted_out_at": "2026-10-01T09:30:00Z",
  "bot_enabled": false,
  "tags": [
    {
      "id": "string",
      "name": "string"
    }
  ],
  "fields": {},
  "created_at": "2026-10-01T09:30:00Z",
  "updated_at": "2026-10-01T09:30:00Z"
}

Delete a contact

deletehttps://api.saei.automize.sa/v1/contacts/{id}
  • Scope: contacts:write
  • Live keys only

Deletes the contact, its tags and custom field values. Campaign messages still queued for them are cancelled. The conversation history stays in the inbox.

Path parameters

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • objectstringrequired
  • deletedtruerequired
Errors this can return3
Try it
curl -X DELETE https://api.saei.automize.sa/v1/contacts/ct_1052 \
  -H "Authorization: Bearer $API_KEY"
Response

Deleted.

{
  "id": "ct_1052",
  "object": "contact",
  "deleted": true
}

Add tags to a contact

posthttps://api.saei.automize.sa/v1/contacts/{id}/tags
  • Scope: contacts:write
  • Live keys only

Adds the tags (ids or names; a new name creates the tag) and keeps the ones the contact already has.

Path parameters

  • idstringrequired

    The object's id.

Request body

  • tagsarray<string>required
Response fields200
  • idstringrequired
  • object"contact"required
  • phonestring | nullrequired
  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional

    The language they prefer, e.g. ar or en.

  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional
  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • opted_inbooleanrequired

    false once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need consent_confirmed.

  • consentobject | nulloptional

    How and when they agreed to business messages, when recorded.

    Child fields (3)
    • sourcestringoptional
    • notestringoptional
    • captured_atstringoptional
  • opted_out_atstring | nulloptional
  • bot_enabledbooleanoptional

    Whether automated replies (flows, AI bots) answer them.

  • tagsarray<object>required
    Child fields (2)
    • idstringoptional
    • namestringoptional
  • fieldsobjectrequired

    Custom field values by key. Values are strings.

  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return4
Try it
curl -X POST https://api.saei.automize.sa/v1/contacts/ct_1052/tags \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "tags": [
    "tag_12",
    "اشترى مؤخرًا"
  ]
}'
Response

The contact with its tags.

{
  "id": "ct_1052",
  "object": "contact",
  "phone": "+966501234567",
  "email": "string",
  "first_name": "string",
  "last_name": "string",
  "language": "string",
  "country": "string",
  "city": "string",
  "gender": "string",
  "birth_date": "string",
  "notes": "string",
  "opted_in": false,
  "consent": {
    "source": "string",
    "note": "string",
    "captured_at": "2026-10-01T09:30:00Z"
  },
  "opted_out_at": "2026-10-01T09:30:00Z",
  "bot_enabled": false,
  "tags": [
    {
      "id": "string",
      "name": "string"
    }
  ],
  "fields": {},
  "created_at": "2026-10-01T09:30:00Z",
  "updated_at": "2026-10-01T09:30:00Z"
}

Remove a tag from a contact

deletehttps://api.saei.automize.sa/v1/contacts/{id}/tags/{tag}
  • Scope: contacts:write
  • Live keys only

Path parameters

  • idstringrequired

    The object's id.

  • tagstringrequired

    The tag id (tag_…) or its name.

Response fields200
  • idstringrequired
  • object"contact"required
  • phonestring | nullrequired
  • emailstring | nulloptional
  • first_namestring | nulloptional
  • last_namestring | nulloptional
  • languagestring | nulloptional

    The language they prefer, e.g. ar or en.

  • countrystring | nulloptional
  • citystring | nulloptional
  • genderstring | nulloptional
  • birth_datestring | nulloptional
  • notesstring | nulloptional
  • opted_inbooleanrequired

    false once they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates need consent_confirmed.

  • consentobject | nulloptional

    How and when they agreed to business messages, when recorded.

    Child fields (3)
    • sourcestringoptional
    • notestringoptional
    • captured_atstringoptional
  • opted_out_atstring | nulloptional
  • bot_enabledbooleanoptional

    Whether automated replies (flows, AI bots) answer them.

  • tagsarray<object>required
    Child fields (2)
    • idstringoptional
    • namestringoptional
  • fieldsobjectrequired

    Custom field values by key. Values are strings.

  • created_atstring | nulloptional
  • updated_atstring | nulloptional
Errors this can return3
Try it
curl -X DELETE https://api.saei.automize.sa/v1/contacts/ct_1052/tags/tag_12 \
  -H "Authorization: Bearer $API_KEY"
Response

The contact without the tag.

{
  "id": "ct_1052",
  "object": "contact",
  "phone": "+966501234567",
  "email": "string",
  "first_name": "string",
  "last_name": "string",
  "language": "string",
  "country": "string",
  "city": "string",
  "gender": "string",
  "birth_date": "string",
  "notes": "string",
  "opted_in": false,
  "consent": {
    "source": "string",
    "note": "string",
    "captured_at": "2026-10-01T09:30:00Z"
  },
  "opted_out_at": "2026-10-01T09:30:00Z",
  "bot_enabled": false,
  "tags": [
    {
      "id": "string",
      "name": "string"
    }
  ],
  "fields": {},
  "created_at": "2026-10-01T09:30:00Z",
  "updated_at": "2026-10-01T09:30:00Z"
}

List tags

gethttps://api.saei.automize.sa/v1/tags
  • Scope: contacts:read
  • Works in test mode

The tags that group your contacts, with how many WhatsApp contacts carry each one.

Query parameters

  • limitintegeroptional

    How many objects to return, 1 to 100.

  • cursorstringoptional

    The next_cursor from the previous page.

  • namestringoptional

    The exact tag name.

Response fields200
  • object"list"required
  • dataarray<Tag>required
    Child fields (5)
    • idstringrequired
    • object"tag"required
    • namestringrequired
    • contact_countintegeroptional
    • created_atstring | nulloptional
  • has_morebooleanrequired
  • next_cursorstring | nullrequired
Errors this can return2
Try it
curl -X GET https://api.saei.automize.sa/v1/tags \
  -H "Authorization: Bearer $API_KEY"
Response

A page of tags.

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

Create a tag

posthttps://api.saei.automize.sa/v1/tags
  • Scope: contacts:write
  • Live keys only
  • Accepts Idempotency-Key

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
Response fields201
  • idstringrequired
  • object"tag"required
  • namestringrequired
  • contact_countintegeroptional
  • created_atstring | nulloptional
Errors this can return4
Try it
curl -X POST https://api.saei.automize.sa/v1/tags \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "عملاء VIP"
}'
Response

Created.

{
  "id": "tag_12",
  "object": "tag",
  "name": "string",
  "contact_count": 0,
  "created_at": "2026-10-01T09:30:00Z"
}

Rename a tag

patchhttps://api.saei.automize.sa/v1/tags/{id}
  • Scope: contacts:write
  • Live keys only

Path parameters

  • idstringrequired

    The object's id.

Request body

  • namestringrequired
Response fields200
  • idstringrequired
  • object"tag"required
  • namestringrequired
  • contact_countintegeroptional
  • created_atstring | nulloptional
Errors this can return4
Try it
curl -X PATCH https://api.saei.automize.sa/v1/tags/tag_12 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "عملاء ذهبيون"
}'
Response

Renamed.

{
  "id": "tag_12",
  "object": "tag",
  "name": "string",
  "contact_count": 0,
  "created_at": "2026-10-01T09:30:00Z"
}

Delete a tag

deletehttps://api.saei.automize.sa/v1/tags/{id}
  • Scope: contacts:write
  • Live keys only

Removes the tag from every contact. The contacts stay.

Path parameters

  • idstringrequired

    The object's id.

Response fields200
  • idstringrequired
  • objectstringrequired
  • deletedtruerequired
Errors this can return3
Try it
curl -X DELETE https://api.saei.automize.sa/v1/tags/tag_12 \
  -H "Authorization: Bearer $API_KEY"
Response

Deleted.

{
  "id": "tag_12",
  "object": "tag",
  "deleted": true
}