Contacts API

Manage contacts for your organization.

Manage contacts for your organization.

Endpoints

MethodPathDescription
GET/api/v1/contactsList contacts
POST/api/v1/contactsCreate contact
GET/api/v1/contacts/:idGet by contact ID or email
PUT/api/v1/contacts/:idUpdate by contact ID or email
DELETE/api/v1/contacts/:idDelete by contact ID or email

List contacts

Contacts are cursor-paginated. There is no row ceiling — every contact is reachable, and search results are genuinely multi-page (relevance-ordered).

GET /api/v1/contacts?limit=25&search=jane

Query params:

  • limit (max 100, default 25)
  • cursor — opaque continuation cursor from the previous response's pagination.cursor. Omit it to fetch the first page.
  • search

Response:

{
  "data": [ /* …contacts… */ ],
  "pagination": {
    "limit": 25,
    "totalItems": 1342,
    "cursor": "opaque-cursor-string",
    "isDone": false
  }
}

To walk every page, keep calling with cursor set to the previous response's pagination.cursor until pagination.isDone is true (at which point cursor is null).

Create contact

POST /api/v1/contacts

Body:

{
  "email": "jane@example.com",
  "firstName": "Jane",
  "lastName": "Smith"
}

Returns 201 with created contact.

Get contact

id can be either:

  • Convex contact ID
  • URL-encoded email (for example jane%40example.com)

Update contact

PUT /api/v1/contacts/:id

Partial updates are supported.

Delete contact

DELETE /api/v1/contacts/:id
Custom properties

Custom contact properties (such as language, timezone, and user-defined fields) are managed through the dashboard. The REST API currently handles core contact fields only (email, firstName, lastName, source, createdAt, updatedAt).

Contact response shape

{
  "data": {
    "id": "j57...",
    "email": "jane@example.com",
    "firstName": "Jane",
    "lastName": "Smith",
    "source": "api",
    "createdAt": "2026-02-17T14:00:00.000Z",
    "updatedAt": "2026-02-17T14:00:00.000Z"
  }
}