Skip to content

Contacts API

The Contacts API follows the same conventions as Leads API: paginated lists, JSON bodies, JWT auth, tenant-scoped automatically.

List

GET /api/contacts/?account=<account_id>&search=jane
Authorization: Bearer <token>
{
  "count": 84,
  "next": null,
  "previous": null,
  "results": [
    {
      "id": "c012-…",
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "jane@acme.com",
      "phone": "+1 555 1234",
      "title": "VP Engineering",
      "account": { "id": "a001-…", "name": "Acme Corp" },
      "linkedin_url": "https://linkedin.com/in/janedoe",
      "owner": { "id": "u034-…", "email": "rep@yours.com" },
      "custom_fields": { "preferred_channel": "email" },
      "created_at": "2026-02-14T09:22:01Z"
    }
  ]
}

Filterable fields: account, owner, search (matches name, email, phone), tags, created_at__gte, cf_<key>.

Create

POST /api/contacts/
Content-Type: application/json
Authorization: Bearer <token>

{
  "first_name": "Jane",
  "last_name": "Doe",
  "email": "jane@acme.com",
  "phone": "+1 555 1234",
  "title": "VP Engineering",
  "account_id": "a001-…",
  "custom_fields": { "preferred_channel": "email" }
}

account_id is optional, pass null for standalone contacts.

Update / delete

PATCH  /api/contacts/<id>/   # partial
PUT    /api/contacts/<id>/   # full
DELETE /api/contacts/<id>/   # hard delete

DELETE removes the row. There is no soft delete, no ?forget=true variant and no PII scrub step; those were documented here and none of them exists.

No merge

There is no POST /api/contacts/<id>/merge/. Duplicate contacts are resolved by hand.

CSV import

Contacts use a two-step import rather than a single upload, so you can see what a file will do before it does it:

POST /api/contacts/import/preview/
POST /api/contacts/import/commit/

Both take multipart/form-data with a file field, capped at 5 MB. preview parses and validates and reports per-row errors as {row, field, message} without writing anything; commit performs the insert.

Neither is reachable from the web app or the phone yet, so this is an API-only path today.