Skip to main content

Create Contact

Add a new contact to your organization. Campaigns, automations and analytics all resolve to contacts, so this is what everything else targets.

Endpoint​

POST /contacts

Returns: 201 Created

Headers​

HeaderValueRequired
AuthorizationBearer <your-api-key>Yes
Content-Typeapplication/jsonYes

Body Parameters​

ParameterTypeRequiredDescription
emailstringConditionalContact's email address.
phone_numberstringConditionalPhone number in E.164 format (e.g., +966512345678).
external_idstringConditionalYour own identifier for this person. Max 255 characters, unique within your organization.
first_namestringNoFirst name. Max 100 characters.
last_namestringNoLast name. Max 100 characters.
propertiesobjectNoCustom property key-value pairs. Keys must match your organization's custom property schema.
list_idsstring[]NoArray of list IDs to add the contact to upon creation.
At Least One Identifier

You must provide at least one of email, phone_number or external_id. You may provide any combination.

Using external_id​

external_id is the identifier you already use for this person — a user ID from your own database. It outranks email and phone_number everywhere in Arsel, which makes it the right key for two jobs:

  • Migrating from another platform. Set it during import and every later event resolves to the same contact deterministically, even for people whose email you don't have.
  • People whose contact details change. An email or phone can be edited; external_id stays put, so history stays attached to the right person.

Reusing an external_id that another contact already holds returns 409. To find whether you have already imported someone, filter for it on List contacts rather than searching by email.

Custom Properties​

Custom properties let you store additional data on contacts. Define your property schema in the Arsel Dashboard under Audience > Properties before sending values.

{
"properties": {
"company": "Acme Inc",
"age": 30,
"is_vip": true,
"birthdate": "1995-06-15"
}
}

Response​

{
"id": "01957e3a-4b5c-7d8e-9f0a-1b2c3d4e5f6a",
"email": "john.doe@example.com",
"phone_number": "+201234567890",
"external_id": "user_10294",
"first_name": "John",
"last_name": "Doe",
"source": "api",
"properties": {
"company": "Acme Inc"
},
"is_suppressed": false,
"created_at": "2026-03-08T12:00:00.000Z",
"updated_at": "2026-03-08T12:00:00.000Z"
}
FieldTypeDescription
idstringUnique contact ID (UUIDv7)
emailstring | nullContact email address
phone_numberstring | nullContact phone number
external_idstring | nullYour own identifier for this person
first_namestring | nullFirst name
last_namestring | nullLast name
sourcestringHow the contact was created: api, manual, import, transactional
propertiesobjectCustom property values
is_suppressedbooleantrue if the contact has unsubscribed, bounced, been blocked by email validation, or been manually suppressed
created_atstringISO 8601 timestamp
updated_atstringISO 8601 timestamp
tip

Contacts created via the API have their source set to api automatically.


Examples​

Basic Contact​

curl -X POST "https://api.arsel.sa/v1/contacts" \
-H "Authorization: Bearer $ARSEL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe"
}'

With Custom Properties and Lists​

curl -X POST "https://api.arsel.sa/v1/contacts" \
-H "Authorization: Bearer $ARSEL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "sara@example.com",
"phone_number": "+966512345678",
"first_name": "Sara",
"last_name": "Ahmed",
"properties": {
"company": "Acme Inc",
"job_title": "Marketing Manager",
"city": "Riyadh"
},
"list_ids": ["01957e3a-4b5c-7d8e-9f0a-1b2c3d4e5f6a"]
}'

Error Responses​

{
"status_code": 422,
"name": "validation_error",
"message": "At least one of email or phone_number must be provided"
}