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.

All endpoints live under 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

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

FieldRequiredTypeDescription
fnameYesStringFirst name. Up to 255 characters.
mnameNoStringMiddle name. Up to 255 characters.
lnameNoStringLast name. Up to 255 characters.
mobileYesStringPhone 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.
emailNoStringA valid email address, up to 60 characters.
cityNoStringUp to 255 characters.
companyNoStringUp to 255 characters.
jobNoStringJob title, up to 255 characters. Saved, but not included in API responses.
Phone numbers are not reformatted. 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.

GET/api/v1/contacts
Query parameters
FieldRequiredTypeDescription
projectYesStringYour project’s exact name.
groupNoStringName 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.
pageNoIntegerPage 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
FieldTypeDescription
groupStringThe name of the group the list was filtered to, or an empty string when no group filter was applied.
contacts.data[]ArrayThe 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_pageNumberThe page returned.
contacts.per_pageNumberAlways 1000.
contacts.totalNumberContacts matching the request, across all pages.
contacts.last_pageNumberThe last page number.
contacts.next_page_urlStringURL 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.

GET/api/v1/contacts/{id}
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.

POST/api/v1/contacts
Request body
FieldRequiredTypeDescription
projectYesStringYour project’s exact name.
contactsYesArrayUp to 1,000 contact objects, each with the contact fields (fname and mobile required).
groupNoStringThe 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
ConditionHTTPResponse 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
{
    "errors": {
        "contacts.0.fname": ["The contacts.0.fname field is required."],
        "contacts.0.mobile": ["The contacts.0.mobile must be a string."],
        "contacts.1.email": ["The contacts.1.email must be a valid email address."]
    }
}
More than 1,000 contacts in one call. Nothing is saved. 400
{
    "error": "You can only create 1000 contacts at a time"
}
contacts is missing or is not an array, or a value is longer than its limit. 500
{
    "error_code": "SERVICE_UNAVAILABLE",
    "message": "An unexpected error occurred. Please retry.",
    "retryable": true
}

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.

PUT/api/v1/contacts/{id}
An update replaces the whole contact. 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
FieldRequiredTypeDescription
projectYesStringYour project’s exact name.
contactYesObjectThe contact fields (fname and mobile required).
groupNoStringThe 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
ConditionHTTPResponse body
contact.fname or contact.mobile missing, a value not a string, or an invalid email. 422
{
    "errors": {
        "contact.fname": ["The contact.fname field is required."],
        "contact.mobile": ["The contact.mobile field is required."]
    }
}
No contact matches {id} in your project (or in the given group). 404
{
    "error": "Contact not found"
}
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.

DELETE/api/v1/contacts/{id}
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.