Contacts
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":
{
"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 aPATCH,tagsreplaces the contact's tags. To add without removing, usePOST /contacts/{id}/tags; to remove one,DELETE /contacts/{id}/tags/{tag}. - Custom fields go in
fields, by the keys fromGET /contact_fields. Values are checked against the field: a number, a date asYYYY-MM-DD, or one of a list's options. An empty value clears the field. Values come back as strings.
Consent#
opted_in says whether the contact accepts business messages.
- Opting out.
PATCHwith"opted_in": falseworks like the customer sending STOP: campaign messages queued for them are cancelled, and templates to them needconsent_confirmedfrom then on. - Opting back in needs a record of how they agreed:
"opted_in": true, "consent": {"source": "paper_form"}. Sources arewebsite_form,paper_form,existing_customer,whatsapp_conversation, orotherwith anote. - Customers can also opt out and in themselves by message (see Arabic & Saudi specifics). You hear about it through
contact.opted_outandcontact.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:
| Event | When |
|---|---|
contact.created | A contact was added |
contact.updated | Details, tags or fields changed |
contact.opted_out / contact.opted_in | Consent changed |
contact.deleted | The 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
- getList custom contact fields
/contact_fields - getList contacts
/contacts - postCreate a contact
/contacts - postCreate or update a contact by phone
/contacts/upsert - getGet a contact
/contacts/{id} - patchUpdate a contact
/contacts/{id} - DELDelete a contact
/contacts/{id} - postAdd tags to a contact
/contacts/{id}/tags - DELRemove a tag from a contact
/contacts/{id}/tags/{tag} - getList tags
/tags - postCreate a tag
/tags - patchRename a tag
/tags/{id} - DELDelete a tag
/tags/{id}
List custom contact fields
https://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· Every custom field, in the portal's order.
object"list"requireddataarray<ContactField>requiredChild fields (7)
idstringrequiredobject"contact_field"requiredkeystringrequiredlabelstringrequiredtypestringrequiredOne of
textnumberdateselectoptionsarray | nulloptionalThe allowed values of a
selectfield.requiredbooleanrequired
has_morebooleanrequirednext_cursorstring | nullrequired
Errors this can return1
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/contact_fields \
-H "Authorization: Bearer $API_KEY"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
https://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
limitintegeroptionalHow many objects to return, 1 to 100.
cursorstringoptionalThe
next_cursorfrom the previous page.phonestringoptionalemailstringoptionaltagstringoptionalA tag id (
tag_…) or name.opted_inbooleanoptionalupdated_sincestringoptionalOnly contacts changed at or after this time (ISO 8601).
Response fields200· A page of contacts.
object"list"requireddataarray<Contact>requiredChild fields (20)
idstringrequiredobject"contact"requiredphonestring | nullrequiredemailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalThe language they prefer, e.g.
aroren.countrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalbirth_datestring | nulloptionalnotesstring | nulloptionalopted_inbooleanrequiredfalseonce they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates needconsent_confirmed.consentobject | nulloptionalHow and when they agreed to business messages, when recorded.
Child fields (3)
sourcestringoptionalnotestringoptionalcaptured_atstringoptional
opted_out_atstring | nulloptionalbot_enabledbooleanoptionalWhether automated replies (flows, AI bots) answer them.
tagsarray<object>requiredChild fields (2)
idstringoptionalnamestringoptional
fieldsobjectrequiredCustom field values by key. Values are strings.
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/contacts \
-H "Authorization: Bearer $API_KEY"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
https://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-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
phonestringoptionalAny format; stored as E.164. Saudi numbers written locally (
0501234567) are understood.emailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalcountrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalOne of
malefemaleotherprefer_not_to_saynullbirth_datestring | nulloptionalnotesstring | nulloptionalbot_enabledbooleanoptionaltagsarray<string>optionalTag ids (
tag_…) or names. A name that does not exist is created.fieldsobjectoptionalCustom field values by key, checked against the field's type (number, date as YYYY-MM-DD, or one of a select's options).
opted_inbooleanoptionalconsentobjectoptionalHow they agreed:
website_form,paper_form,existing_customer,whatsapp_conversation, orotherwith anote.Child fields (2)
sourcestringrequiredOne of
website_formpaper_formexisting_customerwhatsapp_conversationothernotestringoptional
Response fields201· Created.
idstringrequiredobject"contact"requiredphonestring | nullrequiredemailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalThe language they prefer, e.g.
aroren.countrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalbirth_datestring | nulloptionalnotesstring | nulloptionalopted_inbooleanrequiredfalseonce they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates needconsent_confirmed.consentobject | nulloptionalHow and when they agreed to business messages, when recorded.
Child fields (3)
sourcestringoptionalnotestringoptionalcaptured_atstringoptional
opted_out_atstring | nulloptionalbot_enabledbooleanoptionalWhether automated replies (flows, AI bots) answer them.
tagsarray<object>requiredChild fields (2)
idstringoptionalnamestringoptional
fieldsobjectrequiredCustom field values by key. Values are strings.
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return7
- 402quota_exceededAllowance used up
- 403test_mode_unsupportedNot in test mode
- 422parameter_missingMissing parameter
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
- 409resource_existsAlready exists
- 429rate_limitedToo many requests
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"
}
}'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
https://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-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
phonestringoptionalAny format; stored as E.164. Saudi numbers written locally (
0501234567) are understood.emailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalcountrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalOne of
malefemaleotherprefer_not_to_saynullbirth_datestring | nulloptionalnotesstring | nulloptionalbot_enabledbooleanoptionaltagsarray<string>optionalTag ids (
tag_…) or names. A name that does not exist is created.fieldsobjectoptionalCustom field values by key, checked against the field's type (number, date as YYYY-MM-DD, or one of a select's options).
opted_inbooleanoptionalconsentobjectoptionalHow they agreed:
website_form,paper_form,existing_customer,whatsapp_conversation, orotherwith anote.Child fields (2)
sourcestringrequiredOne of
website_formpaper_formexisting_customerwhatsapp_conversationothernotestringoptional
Response fields200· Updated an existing contact.
idstringrequiredobject"contact"requiredphonestring | nullrequiredemailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalThe language they prefer, e.g.
aroren.countrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalbirth_datestring | nulloptionalnotesstring | nulloptionalopted_inbooleanrequiredfalseonce they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates needconsent_confirmed.consentobject | nulloptionalHow and when they agreed to business messages, when recorded.
Child fields (3)
sourcestringoptionalnotestringoptionalcaptured_atstringoptional
opted_out_atstring | nulloptionalbot_enabledbooleanoptionalWhether automated replies (flows, AI bots) answer them.
tagsarray<object>requiredChild fields (2)
idstringoptionalnamestringoptional
fieldsobjectrequiredCustom field values by key. Values are strings.
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return7
- 402quota_exceededAllowance used up
- 403test_mode_unsupportedNot in test mode
- 422parameter_missingMissing parameter
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
- 409resource_existsAlready exists
- 429rate_limitedToo many requests
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
}
}'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
https://api.saei.automize.sa/v1/contacts/{id}- Scope:
contacts:read - Live keys only
Path parameters
idstringrequiredThe object's id.
Response fields200· The contact.
idstringrequiredobject"contact"requiredphonestring | nullrequiredemailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalThe language they prefer, e.g.
aroren.countrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalbirth_datestring | nulloptionalnotesstring | nulloptionalopted_inbooleanrequiredfalseonce they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates needconsent_confirmed.consentobject | nulloptionalHow and when they agreed to business messages, when recorded.
Child fields (3)
sourcestringoptionalnotestringoptionalcaptured_atstringoptional
opted_out_atstring | nulloptionalbot_enabledbooleanoptionalWhether automated replies (flows, AI bots) answer them.
tagsarray<object>requiredChild fields (2)
idstringoptionalnamestringoptional
fieldsobjectrequiredCustom field values by key. Values are strings.
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/contacts/ct_1052 \
-H "Authorization: Bearer $API_KEY"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
https://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
idstringrequiredThe object's id.
Request body
phonestringoptionalAny format; stored as E.164. Saudi numbers written locally (
0501234567) are understood.emailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalcountrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalOne of
malefemaleotherprefer_not_to_saynullbirth_datestring | nulloptionalnotesstring | nulloptionalbot_enabledbooleanoptionaltagsarray<string>optionalTag ids (
tag_…) or names. A name that does not exist is created.fieldsobjectoptionalCustom field values by key, checked against the field's type (number, date as YYYY-MM-DD, or one of a select's options).
opted_inbooleanoptionalconsentobjectoptionalHow they agreed:
website_form,paper_form,existing_customer,whatsapp_conversation, orotherwith anote.Child fields (2)
sourcestringrequiredOne of
website_formpaper_formexisting_customerwhatsapp_conversationothernotestringoptional
Response fields200· The updated contact.
idstringrequiredobject"contact"requiredphonestring | nullrequiredemailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalThe language they prefer, e.g.
aroren.countrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalbirth_datestring | nulloptionalnotesstring | nulloptionalopted_inbooleanrequiredfalseonce they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates needconsent_confirmed.consentobject | nulloptionalHow and when they agreed to business messages, when recorded.
Child fields (3)
sourcestringoptionalnotestringoptionalcaptured_atstringoptional
opted_out_atstring | nulloptionalbot_enabledbooleanoptionalWhether automated replies (flows, AI bots) answer them.
tagsarray<object>requiredChild fields (2)
idstringoptionalnamestringoptional
fieldsobjectrequiredCustom field values by key. Values are strings.
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return6
- 403test_mode_unsupportedNot in test mode
- 422parameter_missingMissing parameter
- 422parameter_invalidInvalid parameter
- 404resource_missingNot found
- 409resource_existsAlready exists
- 429rate_limitedToo many requests
Try it
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
}
}'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
https://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
idstringrequiredThe object's id.
Response fields200· Deleted.
idstringrequiredobjectstringrequireddeletedtruerequired
Errors this can return3
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 429rate_limitedToo many requests
Try it
curl -X DELETE https://api.saei.automize.sa/v1/contacts/ct_1052 \
-H "Authorization: Bearer $API_KEY"Deleted.
{
"id": "ct_1052",
"object": "contact",
"deleted": true
}Add tags to a contact
https://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
idstringrequiredThe object's id.
Request body
tagsarray<string>required
Response fields200· The contact with its tags.
idstringrequiredobject"contact"requiredphonestring | nullrequiredemailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalThe language they prefer, e.g.
aroren.countrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalbirth_datestring | nulloptionalnotesstring | nulloptionalopted_inbooleanrequiredfalseonce they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates needconsent_confirmed.consentobject | nulloptionalHow and when they agreed to business messages, when recorded.
Child fields (3)
sourcestringoptionalnotestringoptionalcaptured_atstringoptional
opted_out_atstring | nulloptionalbot_enabledbooleanoptionalWhether automated replies (flows, AI bots) answer them.
tagsarray<object>requiredChild fields (2)
idstringoptionalnamestringoptional
fieldsobjectrequiredCustom field values by key. Values are strings.
created_atstring | nulloptionalupdated_atstring | nulloptional
Errors this can return4
- 403test_mode_unsupportedNot in test mode
- 422parameter_missingMissing parameter
- 404resource_missingNot found
- 429rate_limitedToo many requests
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",
"اشترى مؤخرًا"
]
}'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
https://api.saei.automize.sa/v1/contacts/{id}/tags/{tag}- Scope:
contacts:write - Live keys only
Path parameters
idstringrequiredThe object's id.
tagstringrequiredThe tag id (
tag_…) or its name.
Response fields200· The contact without the tag.
idstringrequiredobject"contact"requiredphonestring | nullrequiredemailstring | nulloptionalfirst_namestring | nulloptionallast_namestring | nulloptionallanguagestring | nulloptionalThe language they prefer, e.g.
aroren.countrystring | nulloptionalcitystring | nulloptionalgenderstring | nulloptionalbirth_datestring | nulloptionalnotesstring | nulloptionalopted_inbooleanrequiredfalseonce they opt out (STOP, the portal or the API). Campaigns skip them and marketing templates needconsent_confirmed.consentobject | nulloptionalHow and when they agreed to business messages, when recorded.
Child fields (3)
sourcestringoptionalnotestringoptionalcaptured_atstringoptional
opted_out_atstring | nulloptionalbot_enabledbooleanoptionalWhether automated replies (flows, AI bots) answer them.
tagsarray<object>requiredChild fields (2)
idstringoptionalnamestringoptional
fieldsobjectrequiredCustom field values by key. Values are strings.
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 DELETE https://api.saei.automize.sa/v1/contacts/ct_1052/tags/tag_12 \
-H "Authorization: Bearer $API_KEY"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
https://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
limitintegeroptionalHow many objects to return, 1 to 100.
cursorstringoptionalThe
next_cursorfrom the previous page.namestringoptionalThe exact tag name.
Response fields200· A page of tags.
object"list"requireddataarray<Tag>requiredChild fields (5)
idstringrequiredobject"tag"requirednamestringrequiredcontact_countintegeroptionalcreated_atstring | nulloptional
has_morebooleanrequirednext_cursorstring | nullrequired
Errors this can return2
- 422parameter_invalidInvalid parameter
- 429rate_limitedToo many requests
Try it
curl -X GET https://api.saei.automize.sa/v1/tags \
-H "Authorization: Bearer $API_KEY"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
https://api.saei.automize.sa/v1/tags- Scope:
contacts:write - Live keys only
- Accepts Idempotency-Key
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
namestringrequired
Response fields201· Created.
idstringrequiredobject"tag"requirednamestringrequiredcontact_countintegeroptionalcreated_atstring | nulloptional
Errors this can return4
- 403test_mode_unsupportedNot in test mode
- 422parameter_missingMissing parameter
- 409resource_existsAlready exists
- 429rate_limitedToo many requests
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"
}'Created.
{
"id": "tag_12",
"object": "tag",
"name": "string",
"contact_count": 0,
"created_at": "2026-10-01T09:30:00Z"
}Rename a tag
https://api.saei.automize.sa/v1/tags/{id}- Scope:
contacts:write - Live keys only
Path parameters
idstringrequiredThe object's id.
Request body
namestringrequired
Response fields200· Renamed.
idstringrequiredobject"tag"requirednamestringrequiredcontact_countintegeroptionalcreated_atstring | nulloptional
Errors this can return4
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 409resource_existsAlready exists
- 429rate_limitedToo many requests
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": "عملاء ذهبيون"
}'Renamed.
{
"id": "tag_12",
"object": "tag",
"name": "string",
"contact_count": 0,
"created_at": "2026-10-01T09:30:00Z"
}Delete a tag
https://api.saei.automize.sa/v1/tags/{id}- Scope:
contacts:write - Live keys only
Removes the tag from every contact. The contacts stay.
Path parameters
idstringrequiredThe object's id.
Response fields200· Deleted.
idstringrequiredobjectstringrequireddeletedtruerequired
Errors this can return3
- 403test_mode_unsupportedNot in test mode
- 404resource_missingNot found
- 429rate_limitedToo many requests
Try it
curl -X DELETE https://api.saei.automize.sa/v1/tags/tag_12 \
-H "Authorization: Bearer $API_KEY"Deleted.
{
"id": "tag_12",
"object": "tag",
"deleted": true
}