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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/ping | Verify 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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/contacts | List contacts | contacts:read |
POST | /api/v1/contacts | Create a contact | contacts:write |
GET | /api/v1/contacts/{id} | Retrieve a contact | contacts:read |
PATCH | /api/v1/contacts/{id} | Update a contact | contacts:write |
DELETE | /api/v1/contacts/{id} | Erase a contact's personal data | contacts:write |
GET | /api/v1/contacts/{id}/events | List a contact's timeline | events:read |
GET | /api/v1/contacts/{id}/notes | List a contact's notes | events:read |
POST | /api/v1/contacts/{id}/notes | Add a note | contacts: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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/leads | List leads | leads:read |
POST | /api/v1/leads | Create and route a lead | leads:write |
GET | /api/v1/leads/{id} | Retrieve a lead | leads:read |
POST | /api/v1/leads/{id}/assign | Route or re-route a lead | leads:write |
POST | /api/v1/leads/routing-preview | Preview where a lead would be routed | leads: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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/messages | List messages | messages:read |
POST | /api/v1/messages | Send a text, WhatsApp message or email | messages: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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/calls | List calls | calls:read |
GET | /api/v1/calls/{id} | Retrieve a call with transcript and recording | calls: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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/deals | List deals | deals:read |
POST | /api/v1/deals | Create a deal | deals:write |
GET | /api/v1/deals/{id} | Retrieve a deal | deals:read |
PATCH | /api/v1/deals/{id} | Update a deal | deals:write |
GET | /api/v1/pipelines | List pipelines and their stages | deals:read |
Listings
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/listings | List the workspace's own listings | listings: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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/appointments | List appointments | appointments:read |
POST | /api/v1/appointments | Book an appointment | appointments:write |
GET | /api/v1/appointments/{id} | Retrieve an appointment | appointments:read |
PATCH | /api/v1/appointments/{id} | Reschedule an appointment or record its outcome | appointments:write |
GET | /api/v1/tasks | List tasks | appointments:read |
POST | /api/v1/tasks | Create a follow-up task | appointments: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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/automations | List automations | automations:read |
POST | /api/v1/automations/{id}/enroll | Start an automation for a contact | automations:manage |
GET | /api/v1/personas | List AI personas | automations:read |
GET | /api/v1/campaigns | List outbound campaigns | automations: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
| Method | Path | Summary | Scope |
|---|---|---|---|
GET | /api/v1/webhooks | List webhook subscriptions | webhooks:manage |
POST | /api/v1/webhooks | Subscribe to events | webhooks:manage |
DELETE | /api/v1/webhooks/{id} | Unsubscribe | webhooks:manage |
POST /webhooks — The signing secret is returned exactly once, here. Every delivery carries X-Webhook-Signature: sha256=<hmac> over the exact request body.