Skip to main content

Contacts

The Contacts API provides CRUD access to contacts — the users that belong to a client account (type = client) — plus an ancillary action for setting a contact as the client’s account owner.
New to the API? Start with Getting started (base URL, response envelope, errors, pagination) and Authentication (API keys). Those conventions apply to every endpoint below and are not repeated here.
Identifier note: contacts are addressed by their numeric id. Wherever {id} appears below it is the contact id.

The contact object

All endpoints that return a contact use this shape:
{
  "id": 45,
  "first_name": "Jane",
  "last_name": "Doe",
  "name": "Jane Doe",
  "email": "jane@acme.example",
  "phone": "+1 555 0100",
  "job_position": "Procurement Lead",
  "account_owner": "no",
  "status": "active",
  "client": { "id": 12, "company_name": "Acme Inc" },
  "role": { "id": 2, "name": "Client" },
  "social": {
    "facebook": null,
    "twitter": null,
    "linkedin": null,
    "github": null,
    "dribbble": null
  },
  "dates": {
    "created": "2026-06-15T09:30:00.000000Z",
    "updated": "2026-06-15T09:30:00.000000Z"
  }
}
FieldTypeNotes
idintegerContact id. Used in all URLs.
first_namestring
last_namestring
namestringFull name (first + last).
emailstringUnique across all users.
phonestring|null
job_positionstring|null
account_ownerstringyes or no. Set via the account-owner action.
statusstringContact status (e.g. active).
clientobjectThe client the contact belongs to { id, company_name }.
roleobject{ id, name }.
socialobjectSocial profile handles.
datesobjectcreated, updated.

List / search contacts

GET /api/contacts

Query parameters

ParameterTypeDescription
statusstringFilter by contact status. By default, soft-deleted contacts are excluded.
client_idintegerFilter by the client the contact belongs to.
account_ownerstringFilter by account owner flag (yes|no).
searchstringFree-text search on first/last name, email and phone.
sortstringfirst_name, last_name, email, created, updated.
orderstringasc or desc (default asc).
limitintegerResults per page (max 100).
pageintegerPage number.

Example request

curl -G https://your-domain/api/contacts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d client_id=12 \
  -d limit=25
<?php
$query = http_build_query(['client_id' => 12, 'limit' => 25]);
$ch = curl_init("https://your-domain/api/contacts?$query");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Example response — 200 OK

{
  "data": [ { "id": 45, "name": "Jane Doe" } ],
  "meta": { "current_page": 1, "per_page": 25, "total": 1, "last_page": 1 },
  "message": "Contacts retrieved successfully."
}

Get a contact

GET /api/contacts/{id}

Example request

curl https://your-domain/api/contacts/45 \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init('https://your-domain/api/contacts/45');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Returns the contact (200) with message “Contact retrieved successfully.”

Create a contact

POST /api/contacts
Creates a contact (client-type user) under an existing client account. A password is generated automatically. A welcome email is not sent unless you pass send_email=yes. The email must be unique across all users — a duplicate returns a 422.

Body parameters

ParameterTypeRequiredNotes
first_namestringyes
last_namestringyes
emailstringyesMust be unique across all users.
clientidintegeryesExisting client id the contact belongs to.
phonestringno
positionstringnoJob position.
send_emailstringnoyes to send the welcome email. Default no.

Example request

curl -X POST https://your-domain/api/contacts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d first_name=Jane \
  -d last_name=Doe \
  -d email=jane@acme.example \
  -d clientid=12
<?php
$ch = curl_init('https://your-domain/api/contacts');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => http_build_query([
        'first_name' => 'Jane',
        'last_name'  => 'Doe',
        'email'      => 'jane@acme.example',
        'clientid'   => 12,
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Example response — 201 Created

{
  "data": { "id": 45, "name": "Jane Doe" },
  "message": "Contact created successfully."
}

Update a contact

PATCH /api/contacts/{id}
first_name, last_name and email are required. The account owner is not changed here — use the account-owner action.

Body parameters

ParameterTypeRequiredNotes
first_namestringyes
last_namestringyes
emailstringyesMust remain unique (the current contact is ignored).
phonestringno
positionstringnoJob position.

Example request

curl -X PATCH https://your-domain/api/contacts/45 \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d first_name=Jane \
  -d last_name=Smith \
  -d email=jane@acme.example
<?php
$ch = curl_init('https://your-domain/api/contacts/45');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PATCH',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
    CURLOPT_POSTFIELDS     => http_build_query([
        'first_name' => 'Jane',
        'last_name'  => 'Smith',
        'email'      => 'jane@acme.example',
    ]),
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Example response — 200 OK

{
  "data": { "id": 45, "name": "Jane Smith" },
  "message": "Contact updated successfully."
}

Delete a contact

DELETE /api/contacts/{id}
Soft-deletes the contact (the account is marked deleted and its email/password are cleared), mirroring the web application’s delete behaviour. Once deleted, the contact is treated as gone: it no longer appears in listings and any subsequent request for it by id (get, update, delete, account-owner) returns 404.

Example request

curl -X DELETE https://your-domain/api/contacts/45 \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init('https://your-domain/api/contacts/45');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'DELETE',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);

Example response — 200 OK

{
  "data": { "id": 45 },
  "message": "Contact deleted successfully."
}

Set as account owner

PUT /api/contacts/{id}/account-owner
Promotes the contact to the account owner of its client. This replaces the client’s previous account owner. No request body is required.
curl -X PUT https://your-domain/api/contacts/45/account-owner \
  -H "Authorization: Bearer YOUR_API_KEY"
<?php
$ch = curl_init('https://your-domain/api/contacts/45/account-owner');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => 'PUT',
    CURLOPT_HTTPHEADER     => ['Authorization: Bearer YOUR_API_KEY'],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Returns the contact (200) with account_owner now yes and message “Contact set as account owner successfully.”

Errors

See Getting started for the shared error format. Contact-specific:
StatusMeaning
404 Not FoundThe contact id does not exist, or the contact has been deleted.
409 ConflictThe contact does not belong to a client account (account-owner action).
422 Unprocessable EntityValidation failed (see below).
{
  "message": "The given data was invalid.",
  "errors": {
    "email": ["The email has already been taken."],
    "first_name": ["The first name field is required."]
  }
}