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
| Method | Endpoint | Description |
|---|---|---|
| GET | /modules/{module}/records | List records with filtering and pagination |
| GET | /modules/{module}/records/{id} | Get a single record |
| POST | /modules/{module}/records | Create a new record |
| PATCH | /modules/{module}/records/{id} | Update an existing record |
| DELETE | /modules/{module}/records/{id} | Delete a record |
| POST | /modules/{module}/records/bulk | Bulk update multiple records |
| POST | /modules/{module}/records/bulk-delete | Bulk 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
| Field | Type | Description |
|---|---|---|
id | string | Unique record identifier |
moduleId | string | ID of the parent module |
moduleSlug | string | URL-friendly module identifier |
displayName | string | Primary display name for the record |
fields | object | Custom field values (keys are field slugs) |
labelIds | string[] | Applied label IDs |
typeIds | string[] | Applied type IDs |
privacyLevel | string | Visibility: account, team, or private |
descriptionHtml | string | Rich text description |
createdDateTime | string | ISO 8601 creation timestamp |
updatedDateTime | string | ISO 8601 last update timestamp |
createdByUserId | string | User ID who created the record |
updatedByUserId | string | User ID who last updated the record |
version | number | Optimistic 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
| Parameter | Type | Description | Example |
|---|---|---|---|
search | string | Full-text search across indexed fields | ?search=john+smith |
sortField | string | Field slug to sort by | ?sortField=created_at |
sortDirection | string | Sort order: asc or desc | ?sortDirection=desc |
labelIds | string | Comma-separated label IDs | ?labelIds=lbl_1,lbl_2 |
typeIds | string | Comma-separated type IDs | ?typeIds=type_customer |
filter[field] | string | Filter by field value | ?filter[status]=active |
advancedFilter | string | JSON-encoded advanced filter | See Advanced Filtering |
page | number | Page number (starts at 1) | ?page=2 |
pageSize | number | Results 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
| Field | Type | Required | Description |
|---|---|---|---|
displayName | string | No | Record display name (auto-generated if not provided) |
fields | object | No | Field values keyed by field slug |
labelIds | string[] | No | Label IDs to apply |
typeIds | string[] | No | Type IDs to apply |
privacyLevel | string | No | Visibility: account, team, or private |
descriptionHtml | string | No | Rich 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
| Field | Type | Description |
|---|---|---|
fields | object | Field values to update |
labelIds | string[] | Replace all labels (omit to keep existing) |
typeIds | string[] | Replace all types (omit to keep existing) |
privacyLevel | string | Update visibility level |
descriptionHtml | string | Update 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
| Field | Type | Required | Description |
|---|---|---|---|
recordIds | string[] | Yes | Record IDs to update (max 100) |
addLabelIds | string[] | No | Labels to add to all records |
removeLabelIds | string[] | No | Labels to remove from all records |
addTypeIds | string[] | No | Types to add to all records |
removeTypeIds | string[] | No | Types 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
| Field | Type | Required | Description |
|---|---|---|---|
recordIds | string[] | Yes | Record 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]=technologyAdvanced 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
| Operator | Description | Example |
|---|---|---|
eq | Equals | { "fieldSlug": "status", "operator": "eq", "value": "active" } |
neq | Not equals | { "fieldSlug": "status", "operator": "neq", "value": "closed" } |
gt | Greater than | { "fieldSlug": "deal_value", "operator": "gt", "value": 10000 } |
gte | Greater than or equal | { "fieldSlug": "deal_value", "operator": "gte", "value": 10000 } |
lt | Less than | { "fieldSlug": "deal_value", "operator": "lt", "value": 50000 } |
lte | Less than or equal | { "fieldSlug": "deal_value", "operator": "lte", "value": 50000 } |
contains | Contains substring | { "fieldSlug": "email", "operator": "contains", "value": "@acme.com" } |
notContains | Does not contain | { "fieldSlug": "email", "operator": "notContains", "value": "spam" } |
startsWith | Starts with | { "fieldSlug": "name", "operator": "startsWith", "value": "John" } |
endsWith | Ends with | { "fieldSlug": "email", "operator": "endsWith", "value": ".edu" } |
in | In list | { "fieldSlug": "status", "operator": "in", "values": ["active", "pending"] } |
notIn | Not in list | { "fieldSlug": "status", "operator": "notIn", "values": ["closed", "lost"] } |
isNull | Is empty/null | { "fieldSlug": "phone", "operator": "isNull" } |
isNotNull | Is not empty | { "fieldSlug": "email", "operator": "isNotNull" } |
between | Between two values | { "fieldSlug": "deal_value", "operator": "between", "values": [10000, 50000] } |
before | Date before | { "fieldSlug": "due_date", "operator": "before", "value": "2024-02-01" } |
after | Date 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=descSort Direction
| Value | Description |
|---|---|
asc | Ascending (A-Z, 0-9, oldest first) |
desc | Descending (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
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
page | number | 1 | - | Page number (1-indexed) |
pageSize | number | 25 | 100 | Records 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=50Pagination 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,statusExample 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.
Related Records (References)
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}/referencesExample 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=10Example 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/trashRestore a Record
POST /modules/{module}/records/{id}/restoreBulk Restore
POST /modules/{module}/records/bulk-restoreRequest body:
{
"recordIds": ["rec_deleted1", "rec_deleted2"]
}Permanently Delete
DELETE /modules/{module}/records/{id}/purgeEmpty Trash
POST /modules/{module}/records/empty-trashError Responses
Common Errors
| Status | Code | Description |
|---|---|---|
| 400 | validation_error | Invalid request body or parameters |
| 401 | unauthorized | Missing or invalid API key |
| 403 | forbidden | Insufficient permissions |
| 404 | not_found | Record or module not found |
| 409 | conflict | Version conflict (optimistic locking) |
| 422 | record_limit_exceeded | Workspace record limit reached |
| 429 | rate_limited | Too 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