Skip to content

Contacts API

Contacts API

Contacts represent individual people at organizations. Each contact can have multiple email addresses and phone numbers, and can be associated with an organization.

Endpoints Overview

MethodEndpointDescription
GET/api-v1-contactsList all contacts with filtering, sorting, and pagination
GET/api-v1-contacts/:idGet a single contact with related data
POST/api-v1-contactsCreate a new contact (with optional emails and phones)
PATCH/api-v1-contacts/:idUpdate an existing contact
DELETE/api-v1-contacts/:idSoft delete a contact

Required Scopes

  • Read operations: read:contacts
  • Write operations: write:contacts

List Contacts

List all contacts with support for filtering, sorting, pagination, and expanding related data.

Endpoint: GET /api-v1-contacts

Scope: read:contacts

Query Parameters

Pagination

ParameterTypeDefaultDescription
limitinteger50Number of records per page (max: 100)
pageinteger1Page number for offset-based pagination
per_pageinteger50Alternative to limit for offset-based pagination
cursorstring-Cursor for cursor-based pagination

Filtering

Filters can be applied using the following syntax:

  • Simple equality: ?first_name=John
  • With operator: ?first_name[like]=John or ?created_at[gte]=2024-01-01

Supported operators: eq, ne, gt, gte, lt, lte, like, in

Filterable fields:

  • first_name - Contact’s first name (string)
  • last_name - Contact’s last name (string)
  • job_title - Job title (string)
  • organization_id - Associated organization UUID
  • is_primary - Primary contact flag (boolean)
  • created_at - Creation timestamp (ISO 8601)

Sorting

Use the sort parameter with field name. Prefix with - for descending order.

Examples:

  • ?sort=first_name - Sort by first name ascending
  • ?sort=-created_at - Sort by creation date descending

Sortable fields: first_name, last_name, created_at, updated_at, job_title

Use the include parameter to expand related resources in the response:

?include=organization,emails,phones

Available includes:

  • organization - Include organization details
  • emails - Include contact email addresses
  • phones - Include contact phone numbers

Response

Returns a paginated list of contacts.

Without includes:

{
"data": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "John",
"last_name": "Doe",
"job_title": "Purchasing Manager",
"organization_id": "987e6543-e21b-12d3-a456-426614174999",
"is_primary": true,
"consent_to_record": true,
"metadata": {},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
],
"pagination": {
"total": 250,
"limit": 50,
"page": 1,
"per_page": 50,
"total_pages": 5,
"has_more": true
}
}

With includes:

{
"data": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "John",
"last_name": "Doe",
"job_title": "Purchasing Manager",
"organization_id": "987e6543-e21b-12d3-a456-426614174999",
"is_primary": true,
"consent_to_record": true,
"metadata": {},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"organization": {
"id": "987e6543-e21b-12d3-a456-426614174999",
"name": "Acme Retail Shop",
"status": "active"
},
"contact_emails": [
{
"id": "email-uuid-1",
"email": "john.doe@acme-shop.de",
"type": "work",
"is_primary": true
}
],
"contact_phones": [
{
"id": "phone-uuid-1",
"phone_number": "+49301234567",
"type": "work",
"is_primary": true
}
]
}
],
"pagination": {
"total": 250,
"limit": 50,
"page": 1,
"per_page": 50,
"total_pages": 5,
"has_more": true
}
}

Example Request

Terminal window
curl -X GET "https://your-project.supabase.co/functions/v1/api-v1-contacts?limit=20&include=organization,emails&sort=-created_at" \
-H "Authorization: Bearer YOUR_API_KEY"

Get Single Contact

Retrieve a single contact by its unique ID with all related data.

Endpoint: GET /api-v1-contacts/:id

Scope: read:contacts

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesContact ID

Query Parameters

ParameterTypeDescription
includestringComma-separated list: organization, emails, phones

Note: By default, single contact requests include all related data (organization, emails, phones).

Response

Returns a single contact with all related data.

{
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "John",
"last_name": "Doe",
"job_title": "Purchasing Manager",
"organization_id": "987e6543-e21b-12d3-a456-426614174999",
"is_primary": true,
"consent_to_record": true,
"metadata": {},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"organization": {
"id": "987e6543-e21b-12d3-a456-426614174999",
"name": "Acme Retail Shop",
"status": "active"
},
"contact_emails": [
{
"id": "email-uuid-1",
"email": "john.doe@acme-shop.de",
"type": "work",
"is_primary": true
}
],
"contact_phones": [
{
"id": "phone-uuid-1",
"phone_number": "+49301234567",
"type": "work",
"is_primary": true
}
]
}
}

Example Request

Terminal window
curl -X GET "https://your-project.supabase.co/functions/v1/api-v1-contacts/123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer YOUR_API_KEY"

Error Responses

404 Not Found:

{
"error": {
"code": "NOT_FOUND",
"message": "Contact not found"
}
}

Create Contact

Create a new contact with optional email addresses and phone numbers.

Endpoint: POST /api-v1-contacts

Scope: write:contacts

Request Body

FieldTypeRequiredDescription
first_namestringYesContact’s first name (trimmed, non-empty)
last_namestringNoContact’s last name
job_titlestringNoJob title or role
organization_idUUIDNoAssociated organization (must exist in your company)
is_primarybooleanNoWhether this is the primary contact (default: false)
consent_to_recordbooleanNoGDPR consent for call recording (default: false)
metadataobjectNoCustom metadata as JSON object
emailsarrayNoArray of email objects (see below)
phonesarrayNoArray of phone objects (see below)

Email Object Structure

FieldTypeRequiredDescription
emailstringYesEmail address
typestringNoEmail type (default: “work”)
is_primarybooleanNoPrimary email flag (default: true for first email)

Phone Object Structure

FieldTypeRequiredDescription
phone_numberstringYesPhone number (preferably E.164 format)
typestringNoPhone type (default: “work”)
is_primarybooleanNoPrimary phone flag (default: true for first phone)

Response

Returns the created contact with all related data and a 201 Created status.

{
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "John",
"last_name": "Doe",
"job_title": "Purchasing Manager",
"organization_id": "987e6543-e21b-12d3-a456-426614174999",
"is_primary": true,
"consent_to_record": false,
"metadata": {},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"organization": {
"id": "987e6543-e21b-12d3-a456-426614174999",
"name": "Acme Retail Shop",
"status": "active"
},
"contact_emails": [
{
"id": "email-uuid-1",
"email": "john.doe@acme-shop.de",
"type": "work",
"is_primary": true
}
],
"contact_phones": [
{
"id": "phone-uuid-1",
"phone_number": "+49301234567",
"type": "work",
"is_primary": true
}
]
}
}

Example Request

Terminal window
curl -X POST "https://your-project.supabase.co/functions/v1/api-v1-contacts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"first_name": "John",
"last_name": "Doe",
"job_title": "Purchasing Manager",
"organization_id": "987e6543-e21b-12d3-a456-426614174999",
"is_primary": true,
"emails": [
{
"email": "john.doe@acme-shop.de",
"type": "work",
"is_primary": true
},
{
"email": "john@personal.com",
"type": "personal",
"is_primary": false
}
],
"phones": [
{
"phone_number": "+49301234567",
"type": "work",
"is_primary": true
}
]
}'

Error Responses

400 Validation Error (missing first_name):

{
"error": {
"code": "VALIDATION_ERROR",
"message": "First name is required",
"details": [
{
"field": "first_name",
"message": "First name is required"
}
]
}
}

400 Validation Error (invalid organization):

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Organization not found",
"details": [
{
"field": "organization_id",
"message": "Organization not found or does not belong to your company"
}
]
}
}

Update Contact

Update an existing contact. Only provided fields will be updated. Note: This endpoint does not update emails or phones. Use separate endpoints for managing those.

Endpoint: PATCH /api-v1-contacts/:id

Scope: write:contacts

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesContact ID

Request Body

All fields are optional. Only include fields you want to update.

FieldTypeDescription
first_namestringContact’s first name
last_namestringContact’s last name
job_titlestringJob title or role
organization_idUUID or nullAssociated organization (set to null to remove)
is_primarybooleanPrimary contact flag
consent_to_recordbooleanGDPR consent for call recording
metadataobjectCustom metadata (replaces existing)

Response

Returns the updated contact with all related data.

{
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"first_name": "John",
"last_name": "Doe",
"job_title": "Senior Purchasing Manager",
"organization_id": "987e6543-e21b-12d3-a456-426614174999",
"is_primary": true,
"consent_to_record": true,
"metadata": {},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-16T14:20:00Z",
"organization": {
"id": "987e6543-e21b-12d3-a456-426614174999",
"name": "Acme Retail Shop",
"status": "active"
},
"contact_emails": [
{
"id": "email-uuid-1",
"email": "john.doe@acme-shop.de",
"type": "work",
"is_primary": true
}
],
"contact_phones": [
{
"id": "phone-uuid-1",
"phone_number": "+49301234567",
"type": "work",
"is_primary": true
}
]
}
}

Example Request

Terminal window
curl -X PATCH "https://your-project.supabase.co/functions/v1/api-v1-contacts/123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"job_title": "Senior Purchasing Manager",
"consent_to_record": true
}'

Error Responses

404 Not Found:

{
"error": {
"code": "NOT_FOUND",
"message": "Contact not found"
}
}

400 No Fields:

{
"error": {
"code": "INVALID_REQUEST",
"message": "No fields to update"
}
}

Delete Contact

Soft delete a contact. The contact is not permanently deleted but marked with a deleted_at timestamp and will no longer appear in API responses.

Endpoint: DELETE /api-v1-contacts/:id

Scope: write:contacts

Path Parameters

ParameterTypeRequiredDescription
idUUIDYesContact ID

Response

Returns a deletion confirmation.

{
"data": {
"deleted": true
}
}

Example Request

Terminal window
curl -X DELETE "https://your-project.supabase.co/functions/v1/api-v1-contacts/123e4567-e89b-12d3-a456-426614174000" \
-H "Authorization: Bearer YOUR_API_KEY"

Error Responses

404 Not Found:

{
"error": {
"code": "NOT_FOUND",
"message": "Contact not found"
}
}

Contact Fields Explained

is_primary

Boolean flag indicating whether this contact is the primary contact for their organization. Useful for identifying the main point of contact.

Boolean flag for GDPR compliance. Indicates whether the contact has given consent for call recording. This should be set to true before recording calls with this contact.

metadata

Custom JSON object for storing additional data specific to your use case. The API does not validate the structure of this field.


Multi-Tenant Isolation

All contacts are automatically scoped to your company. You can only access contacts that belong to your company (determined by your API key’s company_id).

When creating a contact with an organization_id, the organization must also belong to your company.


  • Organizations: Contacts can belong to an organization. See Organizations API
  • Deals: Contacts can be associated with deals. See Deals API