Contacts API
Manage your project’s phonebook programmatically — create, read, update and delete contacts, and put them in groups. Groups are what you pick when you send a campaign to a list from the dashboard.
https://sozuri.net/api/v1/contacts. Every request answers with JSON. A contact only exists inside the project that created it: a contact that belongs to another project is answered exactly like one that does not exist.
- Authentication
- Contact fields
- List contacts —
GET /v1/contacts - Get one contact —
GET /v1/contacts/{id} - Create contacts (bulk) —
POST /v1/contacts - Update a contact —
PUT /v1/contacts/{id} - Delete a contact —
DELETE /v1/contacts/{id}
Authentication
Every request carries two things: your project’s API key and the project’s name in a project field. Send the key as a Bearer token, or as an apiKey field in the query string or body. An apiKey header is not read. The project value must be the project’s exact name. See Authentication.
Authorization: Bearer YOUR_PROJECT_API_KEY
Content-Type: application/json
Accept: application/json
On GET and DELETE requests, send project (and any other parameter) in the query string, for example ?project=Your_Project_Name. On POST and PUT, send it in the JSON body.
A missing or wrong key, or a missing or wrong project name, is refused before anything else runs:
HTTP 401
{
"error_code": "AUTHENTICATION_FAILED",
"message": "Authentication failed. Check your API key or bearer token.",
"retryable": false
}
Contact fields
| Field | Required | Type | Description |
|---|---|---|---|
| fname | Yes | String | First name. Up to 255 characters. |
| mname | No | String | Middle name. Up to 255 characters. |
| lname | No | String | Last name. Up to 255 characters. |
| mobile | Yes | String | Phone number, sent as a JSON string (a JSON number is refused). Up to 255 characters. Stored exactly as you send it — see the note below. |
| No | String | A valid email address, up to 60 characters. | |
| city | No | String | Up to 255 characters. |
| company | No | String | Up to 255 characters. |
| job | No | String | Job title, up to 255 characters. Saved, but not included in API responses. |
mobile is saved exactly as sent. Sending to a group copes with any common format, but looking a contact up by number matches the exact saved text: a contact saved as 0700000000 is not found as 254700000000. Use one format everywhere — we recommend 2547XXXXXXXX. Creating a contact does not check for an existing contact with the same number.
Text longer than the limits above is not accepted: the request fails with HTTP 500 and the generic error body {"error_code": "SERVICE_UNAVAILABLE", "message": "An unexpected error occurred. Please retry.", "retryable": true}. The API does not read or set a contact’s notes.
List contacts
Returns the project’s contacts, 1,000 per page. Pass group to return only the contacts in that group.
Query parameters
| Field | Required | Type | Description |
|---|---|---|---|
| project | Yes | String | Your project’s exact name. |
| group | No | String | Name of one of your groups. If no group in your project has this name, the filter is ignored and all contacts are returned with "group": "" — check the group field in the response. |
| page | No | Integer | Page to return, starting at 1 (default 1). The page size is fixed at 1,000. A page past the end returns an empty data array. |
Sample request
curl 'https://sozuri.net/api/v1/contacts?project=Your_Project_Name&group=vip-customers&page=1' \
--header 'Authorization: Bearer YOUR_PROJECT_API_KEY' \
--header 'Accept: application/json'
Sample response (200)
{
"group": "vip-customers",
"contacts": {
"current_page": 1,
"data": [
{
"id": 101,
"fname": "Jane",
"mname": null,
"lname": "Doe",
"mobile": "254700000001",
"email": "[email protected]",
"city": "Nairobi",
"company": "Example Ltd",
"created_at": "2026-11-08T07:00:00.000000Z"
},
{
"id": 102,
"fname": "John",
"mname": null,
"lname": null,
"mobile": "254700000002",
"email": null,
"city": null,
"company": null,
"created_at": "2026-11-08T07:05:12.000000Z"
}
],
"first_page_url": "https://sozuri.net/api/v1/contacts?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://sozuri.net/api/v1/contacts?page=1",
"links": [
{ "url": null, "label": "« Previous", "active": false },
{ "url": "https://sozuri.net/api/v1/contacts?page=1", "label": "1", "active": true },
{ "url": null, "label": "Next »", "active": false }
],
"next_page_url": null,
"path": "https://sozuri.net/api/v1/contacts",
"per_page": 1000,
"prev_page_url": null,
"to": 2,
"total": 2
}
}
Response fields
| Field | Type | Description |
|---|---|---|
| group | String | The name of the group the list was filtered to, or an empty string when no group filter was applied. |
| contacts.data[] | Array | The contacts on this page. Each has id, fname, mname, lname, mobile, email, city, company and created_at (ISO 8601, UTC). Missing values are null. The order is not guaranteed. |
| contacts.current_page | Number | The page returned. |
| contacts.per_page | Number | Always 1000. |
| contacts.total | Number | Contacts matching the request, across all pages. |
| contacts.last_page | Number | The last page number. |
| contacts.next_page_url | String | URL of the next page, or null on the last page. It carries only page: add your project, key and group again when you follow it. |
Get one contact
Fetch a single contact by its numeric id. If no contact in your project has that id, the value is matched against the contacts’ mobile instead, so you can also look a contact up by its number (exactly as it was saved; URL-encode a leading +). If several contacts share the number, one of them is returned.
Sample request
curl 'https://sozuri.net/api/v1/contacts/101?project=Your_Project_Name' \
--header 'Authorization: Bearer YOUR_PROJECT_API_KEY' \
--header 'Accept: application/json'
Sample response (200)
{
"contact": {
"id": 101,
"fname": "Jane",
"mname": null,
"lname": "Doe",
"mobile": "254700000001",
"email": "[email protected]",
"city": "Nairobi",
"company": "Example Ltd",
"created_at": "2026-11-08T07:00:00.000000Z"
}
}
Not found (404)
{
"error": "Contact not found"
}
Create contacts (bulk)
Add up to 1,000 contacts in one call. Every contact created by a call goes into one group.
Request body
| Field | Required | Type | Description |
|---|---|---|---|
| project | Yes | String | Your project’s exact name. |
| contacts | Yes | Array | Up to 1,000 contact objects, each with the contact fields (fname and mobile required). |
| group | No | String | The group to put the new contacts in. If your project has a group with this name they join it; otherwise a group with this name is created. If you leave it out, a new group named default is created on every call — send a group name to keep contacts together. |
Sample request
POST /api/v1/contacts HTTP/1.1
Host: sozuri.net
Authorization: Bearer YOUR_PROJECT_API_KEY
Content-Type: application/json
Accept: application/json
{
"project": "Your_Project_Name",
"group": "vip-customers",
"contacts": [
{
"fname": "Jane",
"lname": "Doe",
"mobile": "254700000001",
"email": "[email protected]",
"city": "Nairobi",
"company": "Example Ltd"
},
{
"fname": "John",
"mobile": "254700000002"
}
]
}
Sample response (201)
{
"message": "Contacts created successfully"
}
The response does not return the new contacts’ ids; list the group to read them.
Errors
| Condition | HTTP | Response body |
|---|---|---|
A contact is missing fname or mobile, a value is not a string, or an email is invalid. Keys name the contact by its position in the array. Nothing is saved. |
422 | |
| More than 1,000 contacts in one call. Nothing is saved. | 400 | |
contacts is missing or is not an array, or a value is longer than its limit. |
500 | |
Contacts are saved one at a time, in order. If a value is too long, the contacts before it in the array are already saved and the rest are not.
Update a contact
Replace a contact’s details. {id} is the contact’s numeric id or, as with Get one contact, its saved mobile number.
fname, mname, lname, mobile, email, city, company and job are all written from the request: any of them you leave out is cleared. Send every value you want to keep.Groups: with
group set to one of your groups, only a contact already in that group is found, and it stays in it. Without group (or with a name that is not one of your groups) any contact in the project is found, and it is removed from its group. An update cannot move a contact to another group.
Request body
| Field | Required | Type | Description |
|---|---|---|---|
| project | Yes | String | Your project’s exact name. |
| contact | Yes | Object | The contact fields (fname and mobile required). |
| group | No | String | The name of the group the contact is in. See the note above. |
Sample request
PUT /api/v1/contacts/101 HTTP/1.1
Host: sozuri.net
Authorization: Bearer YOUR_PROJECT_API_KEY
Content-Type: application/json
Accept: application/json
{
"project": "Your_Project_Name",
"group": "vip-customers",
"contact": {
"fname": "Jane",
"lname": "Doe",
"mobile": "254700000001",
"email": "[email protected]",
"city": "Mombasa",
"company": "Example Ltd"
}
}
Sample response (200)
{
"message": "Contact updated successfully"
}
Errors
| Condition | HTTP | Response body |
|---|---|---|
contact.fname or contact.mobile missing, a value not a string, or an invalid email. |
422 | |
No contact matches {id} in your project (or in the given group). |
404 | |
| A value is longer than its limit. | 500 | The generic error body shown under Create contacts. |
Delete a contact
Permanently remove a contact from your project. {id} is the contact’s numeric id or its saved mobile number; when several contacts share the number, one of them is deleted.
Sample request
curl --request DELETE 'https://sozuri.net/api/v1/contacts/101?project=Your_Project_Name' \
--header 'Authorization: Bearer YOUR_PROJECT_API_KEY' \
--header 'Accept: application/json'
Sample response (200)
{
"message": "Contact deleted successfully"
}
Not found (404)
{
"error": "Contact not found"
}
Use cases
How teams build their messaging audience on top of the Contacts API.
Sync from your CRM
Push new signups from HubSpot, Pipedrive or your own database into Sozuri groups as they happen — campaigns always target the freshest list.
E-commerce abandoned cart
Create a contact when a customer abandons checkout, drop them in an abandoned-cart group, and have your system send a recovery SMS an hour later.
Segmented broadcasts
Build groups like nairobi-vip, mama-mboga, silver-tier and send tailored offers to each — lifts open rates without bloating your stack.
Keep lists clean
When a customer leaves, DELETE their contact so group campaigns stop reaching them. Deleting a contact does not block messages you send to that number directly.
Build a smarter messaging audience.
Pipe your customer data into Sozuri groups today and start sending more relevant SMS and WhatsApp.