Skip to content

Contacts

Manage your CRM contacts, and read the organisations and groups they belong to. Reading requires contacts:read; creating, updating, deleting and (un)subscribing require contacts:write.

GET /v1/contacts
Query paramDescription
cursorPagination cursor.
limitPage size, default 25, max 100.
emailExact, case-insensitive email match.
updated_sinceOnly contacts updated at/after this ISO-8601 UTC timestamp.
unsubscribedtrue = only unsubscribed, false = only subscribed.
Terminal window
curl "https://publicapi.shout.com/v1/contacts?limit=1" \
-H "Authorization: Bearer $SHOUT_API_KEY"
{
"items": [
{
"id": "5ca4c57b-410b-dc21-6542-3a206ef96e4c",
"email": "emery@example.com",
"name": "Emery",
"lastName": "Blake",
"phone": null,
"unsubscribed": false,
"organisationId": null,
"groupIds": [],
"source": "manual",
"createdAt": "2026-04-05T08:40:04.9840437Z",
"updatedAt": "2026-04-05T08:40:04.9840437Z"
}
],
"nextCursor": "djE6NjM5MTA5NzUyMDQ5..."
}

source records where a contact came from: api, manual, import, form, email_ticket, instagram_message, messenger_message, whatsapp_message, or unknown.

GET /v1/contacts/{id}

Returns a single contact in the shape above, or 404 not_found.

POST /v1/contacts

email is required; everything else is optional. Contacts created here are stamped source: "api".

Terminal window
curl -X POST "https://publicapi.shout.com/v1/contacts" \
-H "Authorization: Bearer $SHOUT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "jordan@acme.com",
"name": "Jordan",
"lastName": "Lee",
"phone": "+15551234567",
"groupIds": [218617]
}'

Returns 201 Created with the new contact.

Shout also auto-matches a contact to an organisation by its email domain where it can, so a new contact may come back with an organisationId you didn’t set.

PUT /v1/contacts/{id}

A partial update — omit a field (or send null) to leave it unchanged. For groupIds, null keeps the current membership, while a non-null array (including []) replaces it.

Terminal window
curl -X PUT "https://publicapi.shout.com/v1/contacts/1dcc380c-8076-2a37-5fb8-3a2265f83a67" \
-H "Authorization: Bearer $SHOUT_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "phone": "+15559998888", "groupIds": [218616, 218617] }'

Returns 200 OK with the updated contact.

DELETE /v1/contacts/{id}

Returns 204 No Content, or 404 not_found if there’s no such contact.

POST /v1/contacts/{id}/unsubscribe
POST /v1/contacts/{id}/subscribe

Each returns the updated contact (with unsubscribed flipped). Unsubscribing suppresses the contact from your email sends, honouring their consent — prefer this over deleting.

Terminal window
curl -X POST "https://publicapi.shout.com/v1/contacts/1dcc380c-8076-2a37-5fb8-3a2265f83a67/unsubscribe" \
-H "Authorization: Bearer $SHOUT_API_KEY"
GET /v1/organisations # cursor, limit, domain
GET /v1/organisations/{id}

Read-only. Requires contacts:read. The optional domain filter matches an organisation by its web domain.

{
"items": [
{
"id": "d119ec41-b2e3-efd0-eb14-3a2071058391",
"name": "Acme Inc",
"website": "https://acme.com",
"industry": "Computer Software",
"country": "United States",
"createdAt": "2026-04-05T18:12:31.2679386Z"
}
],
"nextCursor": "djE6NjM5MTEwMDk1..."
}
GET /v1/groups

Read-only, requires contacts:read. Groups (contact lists) are small per tenant, so returned unpaginated. Use a group’s id in a contact’s groupIds.

{
"items": [
{ "id": 218617, "type": "standard", "name": "Form Sign-Ups", "memberCount": 42 },
{ "id": 218616, "type": "standard", "name": "Marketing", "memberCount": 1180 }
],
"nextCursor": null
}

type is standard or all_contacts (the built-in list of everyone). Group ids are integers, not UUIDs.