API reference
Contacts API
Reference for creating, listing, retrieving, updating and deleting contacts, and managing their segments and topics.
The contacts API manages the contacts of the project that owns your API key. Every endpoint needs a full_access key. For the concepts, see Contacts.
In every path, {identifier} is either the contact ID or the contact's email address.
The contact object
{
"object": "contact",
"id": "jx7r4k9m2c5v8n1b3q6w0e2t",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace",
"unsubscribed": false,
"properties": { "company": "Acme" },
"created_at": "2026-11-14T10:30:00.000Z"
}Create a contact
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | 3 to 320 characters. Stored in lowercase. |
first_name | string | No | Up to 200 characters. |
last_name | string | No | Up to 200 characters. |
unsubscribed | boolean | No | Default false. |
properties | object | No | Values must be strings, numbers or null. Each key must be a declared contact property. |
segments | object[] | No | [{ "id": "..." }]. |
topics | object[] | No | [{ "id": "...", "subscription": "opt_in" }]. subscription is opt_in or opt_out. |
curl -X POST https://api.sooner.dev/contacts \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "ada@example.com",
"first_name": "Ada",
"properties": { "company": "Acme" },
"segments": [{ "id": "jd5f2h8k4m7p1r6t9v3x0z2c" }]
}'{ "object": "contact", "id": "jx7r4k9m2c5v8n1b3q6w0e2t" }Notable errors: validation_error for an invalid email, a duplicate email, an undeclared property or one of the wrong type, or your plan's contact limit. not_found for an unknown segment or topic.
List contacts
Returns the project's contacts, newest first. Accepts limit and after. See Pagination.
curl "https://api.sooner.dev/contacts?limit=2" \
-H "Authorization: Bearer $SOONER_API_KEY"{
"object": "list",
"data": [
{
"object": "contact",
"id": "jx7r4k9m2c5v8n1b3q6w0e2t",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace",
"unsubscribed": false,
"properties": { "company": "Acme" },
"created_at": "2026-11-14T10:30:00.000Z"
}
],
"has_more": false
}Retrieve a contact
curl https://api.sooner.dev/contacts/ada@example.com \
-H "Authorization: Bearer $SOONER_API_KEY"The response is the contact object. Notable errors: not_found.
Update a contact
Changes only the fields you send. properties is merged into the existing values.
| Field | Type | Required | Description |
|---|---|---|---|
first_name | string or null | No | null clears it. |
last_name | string or null | No | null clears it. |
unsubscribed | boolean | No | The global opt-out. |
properties | object | No | Strings, numbers or null. Keys must be declared. |
curl -X PATCH https://api.sooner.dev/contacts/ada@example.com \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "unsubscribed": true }'{ "object": "contact", "id": "jx7r4k9m2c5v8n1b3q6w0e2t" }Delete a contact
curl -X DELETE https://api.sooner.dev/contacts/ada@example.com \
-H "Authorization: Bearer $SOONER_API_KEY"{
"object": "contact",
"contact": "jx7r4k9m2c5v8n1b3q6w0e2t",
"id": "jx7r4k9m2c5v8n1b3q6w0e2t",
"deleted": true
}Add a contact to a segment
curl -X POST https://api.sooner.dev/contacts/ada@example.com/segments/jd5f2h8k4m7p1r6t9v3x0z2c \
-H "Authorization: Bearer $SOONER_API_KEY"{ "id": "jd5f2h8k4m7p1r6t9v3x0z2c" }Adding a contact that is already a member succeeds and changes nothing. Notable errors: not_found for an unknown contact or segment.
Remove a contact from a segment
Removes the membership and keeps the contact.
{ "id": "jd5f2h8k4m7p1r6t9v3x0z2c", "deleted": true }List a contact's segments
Returns every segment the contact is in. The list is not paginated.
{
"object": "list",
"data": [
{
"object": "segment",
"id": "jd5f2h8k4m7p1r6t9v3x0z2c",
"name": "Newsletter subscribers",
"created_at": "2026-11-14T10:00:00.000Z"
}
],
"has_more": false
}Update a contact's topics
Sets the contact's choice for one or more topics. The body is a JSON array.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The topic ID. |
subscription | string | Yes | opt_in or opt_out. |
curl -X PATCH https://api.sooner.dev/contacts/ada@example.com/topics \
-H "Authorization: Bearer $SOONER_API_KEY" \
-H "Content-Type: application/json" \
-d '[{ "id": "jt3b6n9q2w5e8r1y4u7i0o2p", "subscription": "opt_out" }]'{ "id": "jx7r4k9m2c5v8n1b3q6w0e2t" }Notable errors: not_found for an unknown contact or topic.
List a contact's topics
Returns every topic in the project with the contact's effective subscription, which is their own choice or the topic default.
{
"object": "list",
"data": [
{
"id": "jt3b6n9q2w5e8r1y4u7i0o2p",
"name": "Product updates",
"description": "New features and improvements",
"subscription": "opt_out"
}
],
"has_more": false
}Contacts in a segment
The same operations exist under a segment, for Resend compatibility: GET /segments/{id}/contacts, POST /segments/{id}/contacts, GET, PATCH and DELETE /segments/{id}/contacts/{identifier}. See the segments API reference.