Skip to content
Pathbound DOCS

Contacts API

Contacts represent people in your Pathbound CRM. Each contact has a unified profile, an event timeline, conversation history, and a list of notes. Contacts are associated with a company and have a chronological event timeline.

POST /v1/contacts

Required scope: contacts:write

FieldTypeRequiredDescription
emailstringyesContact email address (must be unique).
propertiesobjectnoArbitrary key-value properties for the contact.
visitor_idstring | string[]noWebsite visitor ID(s) from the tracker to associate.
company_idstringnoAssociate the new contact with this company.
{
"status": "success",
"contact": {
"contact_id": "ct_abc",
"_id": "ct_abc",
"properties": {
"email": "[email protected]",
"firstname": "Ada",
"lastname": "Lovelace"
},
"associations": { "companies": ["co_xyz"] },
"first_seen_at": "2026-01-15T10:00:00.000Z",
"segment_ids": [],
"creation_source": "manual",
"created_at": "2026-01-15T10:00:00.000Z",
"updated_at": "2026-01-15T10:00:00.000Z",
"notes": []
}
}

_id is a transitional alias for contact_id and will be removed in a future release — prefer contact_id in new integrations.

Returns 409 Conflict if a contact with the same email already exists.


GET /v1/contacts

Required scope: contacts:read

ParameterTypeDefaultDescription
pagenumber1Page number.
limitnumber20Results per page (1–100).
statusstringFilter: enriched or not_enriched.
lifecycle_stagestringFilter by lifecycle stage (lead, prospect, mql, sql, opportunity, customer, evangelist, subscriber, other).
lead_statusstringFilter by lead status.
countrystringFilter by country.
industrystringFilter by industry.
citystringFilter by city.
statestringFilter by state/region.
job_titlestringFilter by job title (case-insensitive match).
has_linkedinbooleanFilter contacts with/without a LinkedIn profile.
company_idstringFilter by associated company ID.
created_afterstringOnly contacts created after this ISO 8601 date.
created_beforestringOnly contacts created before this ISO 8601 date.
searchstringFree-text search across name, email, company, job title.
sort_bystringField to sort by (email, firstname, lastname, company, createdate).
sort_dirstringdescSort direction (asc or desc).
count_onlybooleanfalseIf true, return only { count } — no records.
fieldsstringsummary (compact identifier + key properties), full (default), or a comma-separated list of field names. Internal fields (tenant_id, user_id, __v, properties_provenance) are blocked from projection.
includestringComma-separated list of optional fields to include. Currently supports provenance to add the per-field source/timestamp record (properties_provenance). Default omits provenance for response-size hygiene.
{
"status": "success",
"contacts": [
{
"contact_id": "ct_abc",
"_id": "ct_abc",
"properties": { "email": "[email protected]", "firstname": "Ada", "lastname": "Lovelace" },
"associations": { "companies": ["co_xyz"] },
"first_seen_at": "2026-01-15T10:00:00.000Z",
"created_at": "2026-01-15T10:00:00.000Z",
"updated_at": "2026-01-15T10:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total_pages": 5,
"total_items": 100
}
}

_id is a transitional alias for contact_id and will be removed in a future release.

For a “how many” question, prefer count_only=true. For multi-entity lookups, use the batch API instead of paginating with filters.


GET /v1/contacts/:contact_id

Required scope: contacts:read

Returns the contact along with its unified profile and (optionally) recent events.

ParameterTypeDefaultDescription
include_eventsbooleantrueIf false, omit the events array and total_events.
events_limitnumber20Max events to include (1–50). Ignored when include_events=false.
includestringComma-separated list of optional fields to include. Supports provenance (per-field provenance on the base contact record) and raw (adds unified_profile.raw_data — the un-deduplicated per-source field dumps; large, omitted by default).
{
"status": "success",
"contact": {
"contact_id": "ct_abc",
"_id": "ct_abc",
"properties": { "email": "[email protected]", "firstname": "Ada", "lastname": "Lovelace" },
"associations": { "companies": ["co_xyz"] },
"_summary": "Ada Lovelace | CTO | at Analytical Engines | London | Stage: customer",
"created_at": "2026-01-15T10:00:00.000Z",
"updated_at": "2026-04-29T12:00:00.000Z"
},
"unified_profile": {
"_id": "ct_abc",
"source_count": 3,
"sources": {
"internal": { "id": "ct_abc", "updated_at": "...", "first_seen_at": "..." },
"hubspot": { "id": "12345", "synced_at": "...", "first_seen_at": "..." },
"apollo": { "id": "ap_678", "enriched_at": "..." }
},
"profile": {
"email": {
"unique_values": [
{ "value": "[email protected]", "sources": [{ "source": "hubspot", "updated_at": "..." }, { "source": "apollo", "updated_at": "..." }] }
],
"all_sources": ["hubspot", "apollo"],
"has_conflict": false
},
"jobtitle": {
"unique_values": [
{ "value": "CTO", "sources": [{ "source": "hubspot", "updated_at": "..." }] },
{ "value": "Chief Technology Officer", "sources": [{ "source": "apollo", "updated_at": "..." }] }
],
"all_sources": ["hubspot", "apollo"],
"has_conflict": true
}
},
"created_at": "...",
"updated_at": "...",
"enriched_at": "..."
},
"events": [
{ "event_id": "evt_1", "_id": "evt_1", "event": "page_view", "timestamp": "...", "url": "...", "title": "..." }
],
"total_events": 42,
"timestamp": "2026-04-29T12:00:00.000Z"
}

_summary is a human-readable one-liner the backend stitches together from the contact’s name, title, company, industry, location, and lifecycle stage. Parts are joined with | and prefixed where applicable (at <company>, Stage: <stage>). Convenient for list views, but not a stable contract — don’t parse it.

unified_profile is the full deduplicated cross-source profile. Each profile field is a multi-source object: unique_values holds every distinct value found across sources (deduplicated), each annotated with the sources that supplied it; all_sources lists every source that had any value for the field; and has_conflict is true when sources disagree (more than one distinct value). sources is a per-source map (presence, external IDs, and sync/enrichment timestamps), and source_count is how many sources contributed. Pass ?include=raw to additionally get raw_data — the verbatim, un-deduplicated per-source field dumps. events is a compact projection of the contact’s most recent events and is omitted (along with total_events) when the request is made with ?include_events=false.

When PII redaction is enabled for an AI-agent (MCP) caller, the personal values inside unified_profile.profile are masked (the field and its source attribution remain visible) and raw_data is never returned, even with ?include=raw.


PUT /v1/contacts/:contact_id

Required scope: contacts:write

FieldTypeRequiredDescription
propertiesobjectnoProperties to update or add (merge).
visitor_idstring | string[]noVisitor ID(s) to associate.

To change a contact’s lifecycle stage, set properties.lifecyclestage to one of the allowed values.

lead, prospect, mql, sql, opportunity, customer, evangelist, subscriber, other.


DELETE /v1/contacts/:contact_id

Required scope: contacts:write

Permanently removes the contact and its notes. Events remain in the audit log.


GET /v1/contacts/events/:contact_id

Required scope: contacts:read

Returns all events associated with a contact. For aggregate event queries (across many contacts), use the Events API directly.

ParameterTypeDefaultDescription
event_typestringFilter by event type.
sort_dirstringdescSort direction (asc or desc).
fieldsstringsummary for a compact projection (event_id, _id, event, timestamp, url, contact_id); omit for full.
includestringComma-separated list of optional fields to include. Currently supports provenance.
{
"status": "success",
"events": [
{
"event_id": "evt_abc",
"_id": "evt_abc",
"event": "page_view",
"timestamp": "2026-04-29T11:23:45.000Z",
"url": "https://example.com/pricing",
"domain": "example.com",
"data": { "title": "Pricing — Example", "path": "/pricing" }
}
],
"contact_id": "ct_abc",
"total_items": 12,
"returned": 12
}

GET /v1/contacts/:contact_id/conversations

Required scope: contacts:read

Returns the contact’s email (Gmail) and Intercom conversation history.

ParameterTypeDefaultDescription
include_messagesbooleanfalseInclude the full message bodies, not just thread metadata.
messages_per_threadnumber5Max messages per thread when include_messages=true.
limitnumber20Total threads to return.

GET /v1/contacts/:contact_id/email-threads

Required scope: contacts:read

Returns a compact list of Gmail threads for the contact — thread_id, last_message_id, subject — useful for joining inbound and outbound communication into a single conversation view.


Each contact can have an unlimited list of free-form notes. Notes are written directly (no approval flow) and are visible to anyone with contacts:read.

GET /v1/contacts/:contact_id/notes

Required scope: contacts:read

POST /v1/contacts/:contact_id/notes

Required scope: contacts:write

FieldTypeRequiredDescription
contentstringyesNote body (markdown).
PATCH /v1/contacts/:contact_id/notes/:note_id

Required scope: contacts:write

DELETE /v1/contacts/:contact_id/notes/:note_id

Required scope: contacts:write