Skip to main content
The Contacts API is organization-scoped. Admin, Manager, and Agent API keys can use the endpoints on this page.
Contacts, interaction history, import previews, and failed-row files can contain personal information. Use synthetic data in staging, restrict exports, and follow your organization’s access and retention policies.

Contact schema

Create requests require primaryPhone. Optional properties are:
String limits are enforced by the API: names are at most 64 characters, phone numbers at most 20, addresses at most 256, and email values must be valid. Unknown request properties are rejected. A contact response includes id, organizationId, the contact fields, channels, createdAt, and updatedAt. GET /contact/:id also includes typed customAttributes entries.

List contacts

GET /contact Query parameters: page, limit, search, sortBy, sortOrder, and include. Search covers name, phone, and email fields. Supported sort fields are firstName, lastName, primaryPhone, primaryEmail, and createdAt. Pass include=customAttributes to embed attribute values.
Response: 200 with the standard { data, meta } pagination envelope. This request does not change data.

Get a contact

GET /contact/:id Path parameter: id, a contact UUID.
Response: 200 with the contact and its custom attributes. Returns 404 when the contact is not present in the API key’s organization.

Create a contact

POST /contact
Example 201 response:
Save contact.id for subsequent requests. Inspect attributeErrors for custom attributes that were not stored. When fullName is omitted, it is constructed from the supplied first and last names. Side effect: creates customer data and a contact interaction. A duplicate primary phone returns 409 rather than silently updating the contact.

Bulk upsert contacts

POST /contact/upsert Existing contacts are matched by primary phone. This endpoint can create and update multiple contacts in one request.
Response: 201 with successCount, failureCount, and failures. Inspect all three fields: HTTP success does not mean every contact succeeded. Correct only failed entries before submitting them again. Example partial-success response:
Side effect: creates or changes contact records. Check existing contacts first when overwriting values would be harmful.

Update a contact

PUT /contact/:id The request is partial despite using PUT: omitted fields remain unchanged, nullable optional fields can be cleared with null, and primaryPhone can be changed but cannot be cleared.
Response: 200 with { contact, attributeErrors }. Inspect attribute errors even when the contact update succeeds. When names change and no explicit full name is supplied, the service rebuilds the full name from the contact names. Returns 404 for an unknown contact and can return 409 when a unique value conflicts. Side effect: changes customer data and can change live-audience membership.

Delete a contact

DELETE /contact/:id
Response: 200 with the soft-deleted contact. Side effect: removes the contact from active use and soft-deletes its audience memberships. Treat this as destructive even though the database operation is a soft delete.

List contact interactions

GET /contact/:id/interactions
Example response:
retentionMonths is returned by the API; do not hardcode its example value. Clients must tolerate new interaction types.

Custom attributes

All custom-attribute endpoints accept Admin, Manager, and Agent API keys. Supported types: text, number, boolean, date, phone_number, email, url, and enum.
Example response:
Deleting an attribute can return 409 CUSTOM_ATTRIBUTE_IN_USE. Its meta.flows identifies flows that still read the field. Remove those references before retrying.

Import contacts

Contact ingestion is a four-request workflow. This import workflow validates Moroccan phone numbers; use an accepted +212 or local Moroccan format and confirm support before importing international numbers. It accepts CSV, XLSX, and XLS files and can optionally link successfully processed contacts to a static audience.

1. Upload

POST /contact/ingestion/upload Multipart fields: file, optional previewRows, optional hasHeaderRow, and optional audienceId.
Response: 201 with sessionId, file metadata, detected columns, preview rows, and expiresAt. Side effect: uploads customer data and creates a temporary ingestion session. Files must not exceed 50 MiB or 100,000 rows, including a header row if present. previewRows defaults to 20 and accepts 1–100. hasHeaderRow defaults to false; set it to true when the first row contains column names. Sessions expire after 30 minutes of inactivity; upload and validate again if expired.

2. Validate mappings

POST /contact/ingestion/validate
Response: 201 with valid, invalid, and existing counts plus previewed rows. Exactly one column must map to primaryPhone. Duplicate phones inside the same file are validation errors; a phone matching an existing contact is shown as an update candidate.

3. Page through validation results

GET /contact/ingestion/validate/:sessionId Query parameters: page, limit (default 50, maximum 500), and filter (all, valid, invalid, or existing).

4. Execute

POST /contact/ingestion/execute
Response: 201 with totalRows, importedCount, createdCount, updatedCount, failedCount, optional failedRowsCsvUrl, and optional audienceLinkedCount. Contact import can succeed even if audience linking fails. Check membership in the selected static audience separately rather than treating import success or audienceLinkedCount as proof of successful additions. Side effects: creates and updates contacts, can add memberships to a static audience, and can produce a temporary failed-row download containing PII. An expired or unknown session returns 404; execution before validation returns 400.

Audiences API

Use imported or API-created contacts in static and live audiences.

Pagination and request retries

Page-based lists use page=1 and limit=20 by default, with a maximum limit of 100, unless the endpoint above specifies an exception. Follow the response’s pagination metadata. See pagination for the response envelope. If a request returns 429, wait for Retry-After when supplied before retrying. For a mutation that times out, check the resource or run before repeating the request; repeating it can duplicate work. See errors for authentication and validation failures.