Skip to main content

Associations API

Link any two records and list a record's associated records. Supported types: leads, opportunities, accounts, contacts, projects, tasks, work_requests; anything else returns 400 Unsupported record type. There is no single RBAC module — the service checks view / edit on the record types involved, and record access on each record. See Associations & Time Entries.

Endpoints​

MethodEndpointDescription
GET/associations/search?type=&q=&limit=Find records of one type to link
GET/associations/:entityType/:entityIdAssociated records grouped by type (manual + derived links)
POST/associationsLink two records
DELETE/associations/:idRemove a manual link (soft delete)

List​

GET /associations/opportunities/:id

Requires view on the record's type and record access to it (else 404). Returns one group per type that has links, in registry order:

[
{
"type": "contacts",
"noun": "contact",
"hiddenCount": 0,
"records": [
{
"id": "uuid",
"label": "Jane Doe",
"subtitle": "Acme Inc",
"url": "/contacts/uuid",
"associationId": null,
"associationLabel": null,
"via": "Opportunity contact",
"removable": false
}
]
},
{
"type": "work_requests",
"noun": "work request",
"hiddenCount": 1,
"records": [
{
"id": "uuid",
"label": "WR-000042 · Product demo for Acme",
"subtitle": "in_progress",
"url": "/work-requests/uuid",
"associationId": null,
"associationLabel": null,
"via": "Requested on this record",
"removable": false
}
]
}
]
FieldMeaning
viaSet when the link comes from the records' own fields (derived); describes where it comes from
associationId, associationLabelSet for manual links; pass associationId to DELETE
removabletrue only for manual links
hiddenCountLinked records of this type the caller may not open (never returned)

POST /associations

{
"sourceType": "work_requests",
"sourceId": "uuid",
"targetType": "contacts",
"targetId": "uuid",
"label": "Demo attendee"
}
  • Requires edit permission on the source type (403 otherwise) and view access to both records (404 otherwise).
  • A record cannot be linked to itself (400).
  • label is optional, trimmed to 100 characters.
  • Idempotent: if the pair is already linked in either direction, the existing link is returned.
{
"id": "uuid",
"sourceType": "work_requests",
"sourceId": "uuid",
"targetType": "contacts",
"targetId": "uuid",
"label": "Demo attendee",
"createdBy": "uuid",
"createdAt": "…"
}

Linking writes an audit entry and a record_linked activity on both records.

DELETE /associations/:id → { "success": true }

Requires edit permission and record access on either linked record (403 otherwise). Only manual links have an id; derived links cannot be removed here. Writes a record_unlinked activity on both records.

Search (Record Picker)​

GET /associations/search?type=accounts&q=acme&limit=20

ParamDescription
typeRegistry type to search
qAt least 2 characters; matched with ILIKE against the type's search columns
limitDefault 20, max 50

Returns [] when the caller lacks view on the type or q is too short. Results are filtered by record access:

[
{ "id": "uuid", "type": "accounts", "label": "Acme Inc", "subtitle": null, "url": "/accounts/uuid" }
]