Records API

Create, read, update, and delete records within your modules

Records are the core data entries in Coherence. Each record belongs to a module and contains field values, labels, types, and metadata. The Records API enables full CRUD operations, bulk actions, filtering, sorting, and pagination.

Overview

Records are individual entries within a module (e.g., a contact in the Contacts module, a deal in the Deals module). Each record has:

  • A unique ID (rec_ prefix)
  • A display name for quick identification
  • Custom field values defined by the module schema
  • Optional labels and types for categorization
  • Metadata including creation/update timestamps and user attribution

Endpoints

MethodEndpointDescription
GET/modules/{module}/recordsList records with filtering and pagination
GET/modules/{module}/records/{id}Get a single record
POST/modules/{module}/recordsCreate a new record
PATCH/modules/{module}/records/{id}Update an existing record
DELETE/modules/{module}/records/{id}Delete a record
POST/modules/{module}/records/bulkBulk update multiple records
POST/modules/{module}/records/bulk-deleteBulk delete multiple records

Record Structure

A record response contains the following fields:

{
  "record": {
    "id": "rec_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "moduleId": "mod_12345678-90ab-cdef-1234-567890abcdef",
    "moduleSlug": "contacts",
    "displayName": "John Smith",
    "fields": {
      "email": "[email protected]",
      "phone": "+1 (555) 123-4567",
      "company": "Acme Corporation",
      "job_title": "VP of Sales",
      "deal_value": 75000,
      "status": "active",
      "last_contacted": "2024-01-15"
    },
    "labelIds": ["lbl_urgent", "lbl_vip"],
    "typeIds": ["type_customer"],
    "privacyLevel": "account",
    "descriptionHtml": "<p>Key decision maker for the enterprise deal.</p>",
    "createdDateTime": "2024-01-10T09:00:00Z",
    "updatedDateTime": "2024-01-15T14:30:00Z",
    "createdByUserId": "usr_abc123",
    "createdByDisplayName": "Sarah Chen",
    "updatedByUserId": "usr_def456",
    "updatedByDisplayName": "Mike Johnson",
    "version": 5
  }
}

Field Descriptions

FieldTypeDescription
idstringUnique record identifier
moduleIdstringID of the parent module
moduleSlugstringURL-friendly module identifier
displayNamestringPrimary display name for the record
fieldsobjectCustom field values (keys are field slugs)
labelIdsstring[]Applied label IDs
typeIdsstring[]Applied type IDs
privacyLevelstringVisibility: account, team, or private
descriptionHtmlstringRich text description
createdDateTimestringISO 8601 creation timestamp
updatedDateTimestringISO 8601 last update timestamp
createdByUserIdstringUser ID who created the record
updatedByUserIdstringUser ID who last updated the record
versionnumberOptimistic locking version number

List Records

Retrieve a paginated list of records from a module with optional filtering and sorting.

GET /modules/{module}/records

Query Parameters

ParameterTypeDescriptionExample
searchstringFull-text search across indexed fields?search=john+smith
sortFieldstringField slug to sort by?sortField=created_at
sortDirectionstringSort order: asc or desc?sortDirection=desc
labelIdsstringComma-separated label IDs?labelIds=lbl_1,lbl_2
typeIdsstringComma-separated type IDs?typeIds=type_customer
filter[field]stringFilter by field value?filter[status]=active
advancedFilterstringJSON-encoded advanced filterSee Advanced Filtering
pagenumberPage number (starts at 1)?page=2
pageSizenumberResults per page (max 100)?pageSize=50

Example Request

curl -X GET "https://api.getcoherence.io/v1/modules/contacts/records?search=acme&filter[status]=active&sortField=created_at&sortDirection=desc&pageSize=25" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Example Response

{
  "records": [
    {
      "id": "rec_abc123",
      "moduleSlug": "contacts",
      "displayName": "John Smith",
      "fields": {
        "email": "[email protected]",
        "company": "Acme Corp",
        "status": "active"
      },
      "labelIds": [],
      "typeIds": ["type_customer"],
      "privacyLevel": "account",
      "createdDateTime": "2024-01-15T10:30:00Z",
      "updatedDateTime": "2024-01-15T14:22:00Z"
    },
    {
      "id": "rec_def456",
      "moduleSlug": "contacts",
      "displayName": "Jane Doe",
      "fields": {
        "email": "[email protected]",
        "company": "Acme Corp",
        "status": "active"
      },
      "labelIds": ["lbl_vip"],
      "typeIds": ["type_lead"],
      "privacyLevel": "account",
      "createdDateTime": "2024-01-14T09:15:00Z",
      "updatedDateTime": "2024-01-14T09:15:00Z"
    }
  ],
  "total": 47,
  "page": 1,
  "pageSize": 25
}

Get Single Record

Retrieve a single record by ID.

GET /modules/{module}/records/{id}

Example Request

curl -X GET "https://api.getcoherence.io/v1/modules/contacts/records/rec_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "record": {
    "id": "rec_abc123",
    "moduleId": "mod_12345678",
    "moduleSlug": "contacts",
    "displayName": "John Smith",
    "fields": {
      "email": "[email protected]",
      "phone": "+1 (555) 123-4567",
      "company": "Acme Corp",
      "job_title": "CEO",
      "status": "active",
      "deal_value": 150000
    },
    "labelIds": ["lbl_vip"],
    "typeIds": ["type_customer"],
    "privacyLevel": "account",
    "descriptionHtml": "<p>Key account, scheduled for quarterly review.</p>",
    "createdDateTime": "2024-01-10T09:00:00Z",
    "updatedDateTime": "2024-01-15T14:30:00Z",
    "createdByUserId": "usr_abc123",
    "createdByDisplayName": "Sarah Chen",
    "updatedByUserId": "usr_def456",
    "updatedByDisplayName": "Mike Johnson",
    "version": 3
  }
}

Create Record

Create a new record in a module.

POST /modules/{module}/records

Request Body

FieldTypeRequiredDescription
displayNamestringNoRecord display name (auto-generated if not provided)
fieldsobjectNoField values keyed by field slug
labelIdsstring[]NoLabel IDs to apply
typeIdsstring[]NoType IDs to apply
privacyLevelstringNoVisibility: account, team, or private
descriptionHtmlstringNoRich text description

Example Request

curl -X POST "https://api.getcoherence.io/v1/modules/contacts/records" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "displayName": "Alice Johnson",
    "fields": {
      "email": "[email protected]",
      "phone": "+1 (555) 987-6543",
      "company": "Tech Startup Inc",
      "job_title": "CTO",
      "status": "lead",
      "source": "conference"
    },
    "labelIds": ["lbl_hot_lead"],
    "typeIds": ["type_lead"],
    "privacyLevel": "account"
  }'

Example Response

{
  "record": {
    "id": "rec_new789",
    "moduleId": "mod_12345678",
    "moduleSlug": "contacts",
    "displayName": "Alice Johnson",
    "fields": {
      "email": "[email protected]",
      "phone": "+1 (555) 987-6543",
      "company": "Tech Startup Inc",
      "job_title": "CTO",
      "status": "lead",
      "source": "conference"
    },
    "labelIds": ["lbl_hot_lead"],
    "typeIds": ["type_lead"],
    "privacyLevel": "account",
    "createdDateTime": "2024-01-16T11:00:00Z",
    "updatedDateTime": "2024-01-16T11:00:00Z",
    "createdByUserId": "usr_abc123",
    "createdByDisplayName": "Sarah Chen",
    "version": 1
  }
}

If you omit the displayName, Coherence will auto-generate one based on the module's display field configuration (typically the first text field or a combination of fields).

Update Record

Update an existing record. Only include fields you want to change.

PATCH /modules/{module}/records/{id}

Request Body

FieldTypeDescription
fieldsobjectField values to update
labelIdsstring[]Replace all labels (omit to keep existing)
typeIdsstring[]Replace all types (omit to keep existing)
privacyLevelstringUpdate visibility level
descriptionHtmlstringUpdate rich text description

Example Request

curl -X PATCH "https://api.getcoherence.io/v1/modules/contacts/records/rec_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "status": "customer",
      "deal_value": 200000,
      "last_contacted": "2024-01-16"
    },
    "labelIds": ["lbl_vip", "lbl_enterprise"]
  }'

Example Response

{
  "record": {
    "id": "rec_abc123",
    "moduleSlug": "contacts",
    "displayName": "John Smith",
    "fields": {
      "email": "[email protected]",
      "phone": "+1 (555) 123-4567",
      "company": "Acme Corp",
      "status": "customer",
      "deal_value": 200000,
      "last_contacted": "2024-01-16"
    },
    "labelIds": ["lbl_vip", "lbl_enterprise"],
    "typeIds": ["type_customer"],
    "privacyLevel": "account",
    "createdDateTime": "2024-01-10T09:00:00Z",
    "updatedDateTime": "2024-01-16T15:45:00Z",
    "version": 4
  }
}

Delete Record

Delete a record. By default, records are soft-deleted and can be restored from trash.

DELETE /modules/{module}/records/{id}

Example Request

curl -X DELETE "https://api.getcoherence.io/v1/modules/contacts/records/rec_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "success": true
}

Deleted records are moved to trash and retained for 30 days. Use the trash endpoints to restore or permanently delete records.

Bulk Operations

Bulk Update

Update multiple records at once. Supports adding/removing labels and types.

POST /modules/{module}/records/bulk

Request Body

FieldTypeRequiredDescription
recordIdsstring[]YesRecord IDs to update (max 100)
addLabelIdsstring[]NoLabels to add to all records
removeLabelIdsstring[]NoLabels to remove from all records
addTypeIdsstring[]NoTypes to add to all records
removeTypeIdsstring[]NoTypes to remove from all records

Example Request

curl -X POST "https://api.getcoherence.io/v1/modules/contacts/records/bulk" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recordIds": ["rec_abc123", "rec_def456", "rec_ghi789"],
    "addLabelIds": ["lbl_reviewed"],
    "removeLabelIds": ["lbl_pending"],
    "addTypeIds": ["type_qualified"]
  }'

Example Response

{
  "records": [
    {
      "id": "rec_abc123",
      "displayName": "John Smith",
      "labelIds": ["lbl_reviewed", "lbl_vip"],
      "typeIds": ["type_customer", "type_qualified"]
    },
    {
      "id": "rec_def456",
      "displayName": "Jane Doe",
      "labelIds": ["lbl_reviewed"],
      "typeIds": ["type_lead", "type_qualified"]
    },
    {
      "id": "rec_ghi789",
      "displayName": "Bob Wilson",
      "labelIds": ["lbl_reviewed"],
      "typeIds": ["type_qualified"]
    }
  ]
}

Bulk Delete

Delete multiple records at once.

POST /modules/{module}/records/bulk-delete

Request Body

FieldTypeRequiredDescription
recordIdsstring[]YesRecord IDs to delete (max 100)

Example Request

curl -X POST "https://api.getcoherence.io/v1/modules/contacts/records/bulk-delete" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recordIds": ["rec_old001", "rec_old002", "rec_old003"]
  }'

Example Response

{
  "deleted": 3,
  "skipped": 0
}

Use bulk endpoints when creating or updating multiple records to reduce API calls and improve performance. Bulk operations are processed in a single transaction for consistency.

Filtering

Simple Field Filters

Filter records by exact field values using the filter[field] query parameter syntax.

# Single value filter
GET /modules/contacts/records?filter[status]=active
 
# Multiple values (OR logic)
GET /modules/contacts/records?filter[status]=active,pending
 
# Multiple fields (AND logic)
GET /modules/contacts/records?filter[status]=active&filter[industry]=technology

Advanced Filtering

For complex filter logic, use the advancedFilter parameter with a JSON-encoded filter object. Advanced filters support operators, grouping, and AND/OR logic.

Filter Operators

OperatorDescriptionExample
eqEquals{ "fieldSlug": "status", "operator": "eq", "value": "active" }
neqNot equals{ "fieldSlug": "status", "operator": "neq", "value": "closed" }
gtGreater than{ "fieldSlug": "deal_value", "operator": "gt", "value": 10000 }
gteGreater than or equal{ "fieldSlug": "deal_value", "operator": "gte", "value": 10000 }
ltLess than{ "fieldSlug": "deal_value", "operator": "lt", "value": 50000 }
lteLess than or equal{ "fieldSlug": "deal_value", "operator": "lte", "value": 50000 }
containsContains substring{ "fieldSlug": "email", "operator": "contains", "value": "@acme.com" }
notContainsDoes not contain{ "fieldSlug": "email", "operator": "notContains", "value": "spam" }
startsWithStarts with{ "fieldSlug": "name", "operator": "startsWith", "value": "John" }
endsWithEnds with{ "fieldSlug": "email", "operator": "endsWith", "value": ".edu" }
inIn list{ "fieldSlug": "status", "operator": "in", "values": ["active", "pending"] }
notInNot in list{ "fieldSlug": "status", "operator": "notIn", "values": ["closed", "lost"] }
isNullIs empty/null{ "fieldSlug": "phone", "operator": "isNull" }
isNotNullIs not empty{ "fieldSlug": "email", "operator": "isNotNull" }
betweenBetween two values{ "fieldSlug": "deal_value", "operator": "between", "values": [10000, 50000] }
beforeDate before{ "fieldSlug": "due_date", "operator": "before", "value": "2024-02-01" }
afterDate after{ "fieldSlug": "created_at", "operator": "after", "value": "2024-01-01" }

Advanced Filter Structure

{
  "root": {
    "id": "group_1",
    "conjunction": "AND",
    "conditions": [
      {
        "id": "cond_1",
        "fieldSlug": "status",
        "operator": "eq",
        "value": "active"
      },
      {
        "id": "group_2",
        "conjunction": "OR",
        "conditions": [
          {
            "id": "cond_2",
            "fieldSlug": "deal_value",
            "operator": "gte",
            "value": 50000
          },
          {
            "id": "cond_3",
            "fieldSlug": "priority",
            "operator": "eq",
            "value": "high"
          }
        ]
      }
    ]
  }
}

Example: Complex Filter Request

Find active contacts with deal value over $50k OR high priority:

curl -X GET "https://api.getcoherence.io/v1/modules/contacts/records" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -G \
  --data-urlencode 'advancedFilter={"root":{"id":"g1","conjunction":"AND","conditions":[{"id":"c1","fieldSlug":"status","operator":"eq","value":"active"},{"id":"g2","conjunction":"OR","conditions":[{"id":"c2","fieldSlug":"deal_value","operator":"gte","value":50000},{"id":"c3","fieldSlug":"priority","operator":"eq","value":"high"}]}]}}'

Sorting

Single Field Sorting

Sort records by a single field using sortField and sortDirection parameters.

# Sort by created date, newest first
GET /modules/contacts/records?sortField=created_at&sortDirection=desc
 
# Sort by name alphabetically
GET /modules/contacts/records?sortField=name&sortDirection=asc
 
# Sort by deal value, highest first
GET /modules/deals/records?sortField=deal_value&sortDirection=desc

Sort Direction

ValueDescription
ascAscending (A-Z, 0-9, oldest first)
descDescending (Z-A, 9-0, newest first)

When no sort is specified, records are returned in reverse chronological order by creation date (newest first).

Pagination

Coherence supports offset-based pagination for record lists.

Pagination Parameters

ParameterTypeDefaultMaxDescription
pagenumber1-Page number (1-indexed)
pageSizenumber25100Records per page

Example: Paginated Request

# First page
GET /modules/contacts/records?page=1&pageSize=50
 
# Second page
GET /modules/contacts/records?page=2&pageSize=50
 
# Third page
GET /modules/contacts/records?page=3&pageSize=50

Pagination Response

{
  "records": [...],
  "total": 247,
  "page": 2,
  "pageSize": 50
}

Calculating Pages

const totalPages = Math.ceil(response.total / response.pageSize);
const hasNextPage = response.page < totalPages;
const hasPrevPage = response.page > 1;

For large datasets with frequent updates, consider using search with filters to narrow results rather than paginating through all records.

Field Selection

Request only specific fields to reduce response size and improve performance.

Query Parameter

Use the fields parameter with comma-separated field slugs:

GET /modules/contacts/records?fields=name,email,status

Example Response

{
  "records": [
    {
      "id": "rec_abc123",
      "displayName": "John Smith",
      "fields": {
        "name": "John Smith",
        "email": "[email protected]",
        "status": "active"
      }
    },
    {
      "id": "rec_def456",
      "displayName": "Jane Doe",
      "fields": {
        "name": "Jane Doe",
        "email": "[email protected]",
        "status": "lead"
      }
    }
  ],
  "total": 247,
  "page": 1,
  "pageSize": 25
}

Core fields like id, displayName, createdDateTime, and updatedDateTime are always included regardless of field selection.

Coherence supports reference fields that link records across modules. Use the references endpoints to work with related data.

List Module References

Get all reference fields defined on a module:

GET /modules/{module}/references

Example Response

{
  "references": [
    {
      "slug": "account",
      "targetModuleSlug": "accounts",
      "targetType": "module",
      "relationshipType": "many_to_one"
    },
    {
      "slug": "owner",
      "targetType": "user",
      "relationshipType": "many_to_one"
    },
    {
      "slug": "related_contacts",
      "targetModuleSlug": "contacts",
      "targetType": "module",
      "relationshipType": "many_to_many"
    }
  ]
}

Get Linked Record IDs

Retrieve the IDs of records linked via a reference field:

GET /modules/{module}/references/{referenceSlug}/records/{recordId}

Example Request

curl -X GET "https://api.getcoherence.io/v1/modules/contacts/references/account/records/rec_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "recordIds": ["rec_acct_001"],
  "records": [
    {
      "id": "rec_acct_001",
      "displayName": "Acme Corporation",
      "moduleSlug": "accounts"
    }
  ]
}

Reference Picker

Search for records to link via a reference field:

GET /modules/{module}/references/{referenceSlug}/picker?search=acme&limit=10

Example Response

{
  "records": [
    {
      "id": "rec_acct_001",
      "label": "Acme Corporation",
      "subtitle": "Technology - Enterprise"
    },
    {
      "id": "rec_acct_002",
      "label": "Acme Startup Labs",
      "subtitle": "Technology - Startup"
    }
  ]
}

Trash and Recovery

Deleted records are soft-deleted and can be recovered within 30 days.

List Deleted Records

GET /modules/{module}/records/trash

Restore a Record

POST /modules/{module}/records/{id}/restore

Bulk Restore

POST /modules/{module}/records/bulk-restore

Request body:

{
  "recordIds": ["rec_deleted1", "rec_deleted2"]
}

Permanently Delete

DELETE /modules/{module}/records/{id}/purge

Empty Trash

POST /modules/{module}/records/empty-trash

Error Responses

Common Errors

StatusCodeDescription
400validation_errorInvalid request body or parameters
401unauthorizedMissing or invalid API key
403forbiddenInsufficient permissions
404not_foundRecord or module not found
409conflictVersion conflict (optimistic locking)
422record_limit_exceededWorkspace record limit reached
429rate_limitedToo many requests

Error Response Format

{
  "error": {
    "code": "validation_error",
    "message": "The email field is required",
    "details": {
      "field": "email",
      "constraint": "required"
    }
  }
}

Validation Error Example

{
  "error": {
    "code": "validation_error",
    "message": "Invalid field values",
    "details": {
      "fields": [
        {
          "field": "email",
          "message": "Invalid email format"
        },
        {
          "field": "deal_value",
          "message": "Must be a positive number"
        }
      ]
    }
  }
}

Related: API Overview | Search API | Activity Log | Webhooks