Developers

API reference

Every endpoint, its scope and its semantics — generated from the route registry.

Read as markdown · OpenAPI 3.1 · llms.txt

The complete endpoint list, generated from the same registry that builds the OpenAPI document — so it cannot describe an endpoint that does not exist, or miss one that does.

The machine-readable spec is at /developers/openapi.json.

Meta

MethodPathSummaryScope
GET/api/v1/pingVerify a credential_any valid credential_

GET /ping — Echoes back which workspace and scopes your credential resolves to. The first call every integration should make.

Contacts

MethodPathSummaryScope
GET/api/v1/contactsList contactscontacts:read
POST/api/v1/contactsCreate a contactcontacts:write
GET/api/v1/contacts/{id}Retrieve a contactcontacts:read
PATCH/api/v1/contacts/{id}Update a contactcontacts:write
DELETE/api/v1/contacts/{id}Erase a contact's personal datacontacts:write
GET/api/v1/contacts/{id}/eventsList a contact's timelineevents:read
GET/api/v1/contacts/{id}/notesList a contact's notesevents:read
POST/api/v1/contacts/{id}/notesAdd a notecontacts:write

DELETE /contacts/{id} — ANONYMIZES in place — it does not delete the row. A contact is referenced by deals, commissions and messages a brokerage is required to keep, so a true delete would either cascade those away or leave them dangling. Names, addresses, message bodies and activity titles are scrubbed; the structural records survive pointing at an anonymized contact.

POST /contacts/{id}/notes — Adding a note pauses the contact's AI auto-response, exactly as it does in the product — a human (or an integration) touching a conversation is the signal that the AI should stop talking over them.

Leads

MethodPathSummaryScope
GET/api/v1/leadsList leadsleads:read
POST/api/v1/leadsCreate and route a leadleads:write
GET/api/v1/leads/{id}Retrieve a leadleads:read
POST/api/v1/leads/{id}/assignRoute or re-route a leadleads:write
POST/api/v1/leads/routing-previewPreview where a lead would be routedleads:read

POST /leads — Creates the lead and routes it through the assignment engine unless skip_routing is set. A lead created WITHOUT a consent object carries no consent artifact, so the pre-dial and pre-send gates will refuse AI outbound to it — the response says so in ai_outbound_allowed.

POST /leads/routing-preview — A dry run: creates nothing, assigns nothing, notifies nobody. Returns the rule that would win, the assignee, and the full considered set with the failing conditions spelled out. For round-robin methods the rotation cursor is NOT advanced, so the live pick may be a different member of the same pool — reason says so.

Messaging

MethodPathSummaryScope
GET/api/v1/messagesList messagesmessages:read
POST/api/v1/messagesSend a text, WhatsApp message or emailmessages:send

POST /messages — Routes through the same send path the product uses, so every compliance check applies: suppression, opt-out, A2P registration, TCPA quiet hours and consent. A refused send returns 422 compliance_blocked with the reason — never a silent success — and the attempt is still recorded in the workspace's inbox.

Calls

MethodPathSummaryScope
GET/api/v1/callsList callscalls:read
GET/api/v1/calls/{id}Retrieve a call with transcript and recordingcalls:read

GET /calls — Includes AI-handled calls with their summaries. handled_by distinguishes AI from human.

GET /calls/{id}recording_url is a five-minute signed link to our own proxy, never the carrier's URL (which is credential-protected and would 401 for you).

Deals

MethodPathSummaryScope
GET/api/v1/dealsList dealsdeals:read
POST/api/v1/dealsCreate a dealdeals:write
GET/api/v1/deals/{id}Retrieve a dealdeals:read
PATCH/api/v1/deals/{id}Update a dealdeals:write
GET/api/v1/pipelinesList pipelines and their stagesdeals:read

Listings

MethodPathSummaryScope
GET/api/v1/listingsList the workspace's own listingslistings:read

GET /listings — These are listings the workspace authored, NOT MLS inventory. MLS data is governed by per-board display rules that a general-purpose REST feed cannot honour.

Calendar

MethodPathSummaryScope
GET/api/v1/appointmentsList appointmentsappointments:read
POST/api/v1/appointmentsBook an appointmentappointments:write
GET/api/v1/appointments/{id}Retrieve an appointmentappointments:read
PATCH/api/v1/appointments/{id}Reschedule an appointment or record its outcomeappointments:write
GET/api/v1/tasksList tasksappointments:read
POST/api/v1/tasksCreate a follow-up taskappointments:write

POST /appointments — Pushes the event out to the creator's connected calendar when one exists, exactly as an in-product booking does.

PATCH /appointments/{id} — Send starts_at AND ends_at together to move it; send outcome to record what happened. Both are separate domain writes, and moving with only one end is refused.

POST /tasks — Deduped within 60 seconds, so a retried webhook does not produce two identical follow-ups. created: false means an identical task already existed.

Automations

MethodPathSummaryScope
GET/api/v1/automationsList automationsautomations:read
POST/api/v1/automations/{id}/enrollStart an automation for a contactautomations:manage
GET/api/v1/personasList AI personasautomations:read
GET/api/v1/campaignsList outbound campaignsautomations:read

POST /automations/{id}/enroll — Returns 202: the enrolment is durable immediately, and the automation runs on the next engine tick. Enrolling into a disabled automation is refused rather than silently dropped.

Webhooks

MethodPathSummaryScope
GET/api/v1/webhooksList webhook subscriptionswebhooks:manage
POST/api/v1/webhooksSubscribe to eventswebhooks:manage
DELETE/api/v1/webhooks/{id}Unsubscribewebhooks:manage

POST /webhooks — The signing secret is returned exactly once, here. Every delivery carries X-Webhook-Signature: sha256=<hmac> over the exact request body.