Contact schema
Create requests requireprimaryPhone. Optional properties are:
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.
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.
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
201 response:
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.
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:
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.
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
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
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.
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.
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
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
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 usepage=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.