For Developers
Outreach

Contacts

Create, search, update and delete the people your agents call.

A contact is a person in your account, identified by a phone number and optionally an email address. Contacts can carry tags and your own metadata, and they feed audiences.

EndpointRequest
List contactsGET/v1/contacts
Get a contactGET/v1/contacts/{id}
Create a contactPOST/v1/contacts
Update a contactPATCH/v1/contacts/{id}
Delete a contactDEL/v1/contacts/{id}

The contact object

Contact fields use snake_case.

Attributes

idstringrequired
The contact's UUID.
first_namestring | null
First name.
last_namestring | null
Last name. null when empty.
namestring
First and last name joined with a space.
phonestring | null
Primary phone number in normalized form.
phone_numberstring | null
Same value as phone.
phone_numbersstring[]
All phone numbers on the contact. The first is the primary number.
emailstring | null
Primary email address, in lowercase.
emailsstring[]
All email addresses on the contact, in lowercase. The first is the primary address.
companystring | null
Company name.
contact_typestring
client, supplier, partner or other. Contacts created through this API are other.
timezonestring
Timezone. Contacts created through this API are UTC.
tagsstring[]
Display names of the tags on the contact.
metadataobject | null
Your own key-value data. Keys that look like internal identifiers, such as user_id and file_id, are left out of responses. Use your own key names, such as crm_id.
created_atstring | null
When the contact was created.
updated_atstring | null
When the contact last changed.

Phone number validation

phone must be a real, dialable number, using the same check as placing a call. So a saved contact can always be called. It can be up to 32 characters, and it is stored in E.164 format.

You sendStored asRule
+1 (202) 555-0123+12025550123Starts with +, so the digits are kept as sent.
555-555-0123+12025550123Ten digits are treated as a US or Canadian number.
12025550123+12025550123Eleven digits starting with 1 get a +.
442079460123+442079460123Anything else gets a + with no other change.

Whatever the form, the result must be valid for its country, or the request returns 400. A national number such as 02025550123 is refused, so send international numbers in E.164 format.

Emails are converted to lowercase before they are stored.

Duplicate contacts

Each account can have only one active contact with a given primary phone number. The same applies to primary email addresses, ignoring case.

POST /v1/contacts doesn't update an existing contact. A request that reuses a phone number or email returns 409 with the code CONFLICT, and no contact is changed. PATCH returns the same error when a new value belongs to another contact. To upsert, search for the number first, then call PATCH or POST based on the result.

A deleted contact doesn't count as a duplicate. Its phone number and email can be used again, and the new contact gets a new id.

List contacts

GET/v1/contactsread key

Returns your active contacts, newest first.

Query parameters

limitintegerdefault 50
Maximum results, from 1 to 100.
offsetintegerdefault 0
Number of results to skip, up to 1,000,000.
searchstring
Filters contacts by name, company, email or phone number, up to 200 characters. A value made only of * returns 400. Leave it out to list everything.

search matches any part of the first name, last name, full name, company or primary email, ignoring case. Phone numbers and additional email addresses match only in full, so search=555 won't find +12025550123. The search value goes through the same normalization as a stored number.

Encode + as %2B in the query string.

Request
curl "https://backend.synthesys.app/api/v1/contacts?limit=10&search=jane" \
  -H "SYNTH_API_KEY: YOUR_API_KEY"
Response
{
  "success": true,
  "data": [
    {
      "id": "3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c",
      "first_name": "Jane",
      "last_name": "Doe",
      "phone_numbers": ["+12025550123"],
      "emails": ["jane@example.com"],
      "contact_type": "other",
      "timezone": "UTC",
      "company": "Example Inc",
      "phone": "+12025550123",
      "phone_number": "+12025550123",
      "name": "Jane Doe",
      "email": "jane@example.com",
      "tags": ["VIP"],
      "metadata": { "crm_id": "A-1001" },
      "created_at": "2026-10-01T09:30:00.000Z",
      "updated_at": "2026-10-01T09:30:00.000Z"
    }
  ],
  "pagination": { "total": 1, "limit": 10, "offset": 0 }
}

Get a contact

GET/v1/contacts/{id}read key

Returns one contact.

Path parameters

idstringrequired
The contact's UUID.

Returns 404 if the contact doesn't exist, belongs to another account or was deleted. An id that isn't a valid UUID returns 400.

Request
curl https://backend.synthesys.app/api/v1/contacts/3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c \
  -H "SYNTH_API_KEY: YOUR_API_KEY"
Response
{
  "success": true,
  "data": {
    "id": "3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c",
    "first_name": "Jane",
    "last_name": "Doe",
    "phone_numbers": ["+12025550123"],
    "emails": ["jane@example.com"],
    "contact_type": "other",
    "timezone": "UTC",
    "company": "Example Inc",
    "phone": "+12025550123",
    "phone_number": "+12025550123",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "tags": ["VIP"],
    "metadata": { "crm_id": "A-1001" },
    "created_at": "2026-10-01T09:30:00.000Z",
    "updated_at": "2026-10-01T09:30:00.000Z"
  }
}
Not found (404)
{
  "success": false,
  "error": "Contact not found",
  "code": "NOT_FOUND",
  "requestId": "e3a1c5d7-2b4f-4a6c-9d8e-1f2a3b4c5d6e",
  "timestamp": "2026-10-31T14:02:11.482Z"
}

Create a contact

POST/v1/contactswrite key

Creates a contact and returns it with status 201. Fields not listed below, such as contact_type and external_id, are ignored.

Body parameters

first_namestringrequired
First name, up to 200 characters. Surrounding spaces are removed, and it can't be empty after that.
phonestringrequired
Phone number, up to 32 characters. See Phone number validation.
last_namestring
Last name, up to 200 characters.
emailstring
A valid email address, up to 320 characters.
companystring
Company name, up to 200 characters.
tagsstring[]
Up to 50 tag names, each 1 to 100 characters. Each must contain a letter, number or underscore. Tags that don't exist yet are created.
metadataobject
Your own key-value data. It can have up to 50 keys and be up to 16 KB, nested up to 5 levels deep.

Tag names match existing tags ignoring case, and the contact shows the tag's existing display name. Names that differ only in spacing or punctuation, such as VIP Lead and vip_lead, count as one tag.

Warnings

If the contact is saved but its tags can't be applied, the request still succeeds. The response adds a warnings array, and the contact is returned without the new tags. Send the tags again with PATCH. Don't repeat the POST, because it would return 409.

JSON
{
  "success": true,
  "data": { "id": "3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c", "first_name": "Jane" },
  "warnings": [
    {
      "code": "TAGS_NOT_APPLIED",
      "message": "The contact was saved, but its tags could not be applied. Send them again with PATCH."
    }
  ]
}

Errors:

  • 400: a field fails validation, first_name or phone is missing, or the number isn't dialable. details.issues names the field.
  • 409: the phone number or email already belongs to an active contact. See duplicate contacts.
Request
curl -X POST https://backend.synthesys.app/api/v1/contacts \
  -H "SYNTH_API_KEY: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Jane",
    "last_name": "Doe",
    "phone": "+12025550123",
    "email": "jane@example.com",
    "company": "Example Inc",
    "tags": ["VIP"],
    "metadata": { "crm_id": "A-1001" }
  }'
Response (201)
{
  "success": true,
  "data": {
    "id": "3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c",
    "first_name": "Jane",
    "last_name": "Doe",
    "phone_numbers": ["+12025550123"],
    "emails": ["jane@example.com"],
    "contact_type": "other",
    "timezone": "UTC",
    "company": "Example Inc",
    "phone": "+12025550123",
    "phone_number": "+12025550123",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "tags": ["VIP"],
    "metadata": { "crm_id": "A-1001" },
    "created_at": "2026-10-01T09:30:00.000Z",
    "updated_at": "2026-10-01T09:30:00.000Z"
  }
}
Validation error (400)
{
  "success": false,
  "error": "The request is invalid.",
  "code": "VALIDATION_ERROR",
  "requestId": "e3a1c5d7-2b4f-4a6c-9d8e-1f2a3b4c5d6e",
  "timestamp": "2026-10-31T14:02:11.482Z",
  "details": {
    "issues": [
      { "path": "phone", "message": "This field is required." }
    ]
  }
}
Duplicate (409)
{
  "success": false,
  "error": "A contact with this phone number or email already exists",
  "code": "CONFLICT",
  "requestId": "1d2c3b4a-5f6e-4d7c-8b9a-0f1e2d3c4b5a",
  "timestamp": "2026-10-31T14:03:40.120Z"
}

Update a contact

PATCH/v1/contacts/{id}write key

Updates only the fields you send and returns the contact. An empty body returns the contact unchanged.

Path parameters

idstringrequired
The contact's UUID.

Body parameters

first_namestring
First name, up to 200 characters. It can't be empty.
last_namestring
Last name, up to 200 characters. An empty string clears it.
phonestring
Replaces all phone numbers on the contact with this one number. See Phone number validation.
emailstring
Replaces all email addresses on the contact with this one address, up to 320 characters.
companystring
Company name, up to 200 characters.
tagsstring[]
Replaces all tags on the contact, up to 50. An empty array removes every tag.
metadataobject
Replaces the whole metadata object, with the same limits as on create. It doesn't merge with existing keys.

A warnings array appears here too if the contact is saved but its tags can't be applied. See Warnings.

Errors:

  • 400: a field fails validation. details.issues names the field.
  • 404: the contact doesn't exist, belongs to another account or was deleted.
  • 409: the new phone number or email already belongs to another active contact.
Request
curl -X PATCH https://backend.synthesys.app/api/v1/contacts/3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c \
  -H "SYNTH_API_KEY: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "company": "Example Group", "tags": ["VIP", "Renewal"] }'
Response
{
  "success": true,
  "data": {
    "id": "3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c",
    "first_name": "Jane",
    "last_name": "Doe",
    "phone_numbers": ["+12025550123"],
    "emails": ["jane@example.com"],
    "contact_type": "other",
    "timezone": "UTC",
    "company": "Example Group",
    "phone": "+12025550123",
    "phone_number": "+12025550123",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "tags": ["VIP", "Renewal"],
    "metadata": { "crm_id": "A-1001" },
    "created_at": "2026-10-01T09:30:00.000Z",
    "updated_at": "2026-10-02T14:05:00.000Z"
  }
}

Delete a contact

DEL/v1/contacts/{id}delete key

Removes a contact from your account. The record is marked as deleted rather than erased, but the API has no way to restore it.

Path parameters

idstringrequired
The contact's UUID.

An id that isn't a valid UUID returns 400.

Deleting a contact has these effects:

  • The contact stops appearing in the contacts endpoints. Reading, updating or deleting it again returns 404.
  • Its tags are removed from it. The tags stay in your account.
  • It is removed from contact lists and from static audiences.
  • It drops out of dynamic audience results.
  • Its phone number and email become available for a new contact.
Request
curl -X DELETE https://backend.synthesys.app/api/v1/contacts/3f2b8c1e-7a4d-4e9b-9c10-5d6e7f8a9b0c \
  -H "SYNTH_API_KEY: YOUR_API_KEY"
Response
{ "success": true, "message": "Contact deleted successfully" }
Not found (404)
{
  "success": false,
  "error": "Contact not found",
  "code": "NOT_FOUND",
  "requestId": "e3a1c5d7-2b4f-4a6c-9d8e-1f2a3b4c5d6e",
  "timestamp": "2026-10-31T14:02:11.482Z"
}