REST API
Read-and-write access to the canonical SMB-operations graph. Every connected tool — and every external caller — speaks the same shape through these endpoints.
What's on this page is what's shipped today. Bearer auth, cursor pagination, idempotency, token-bucket rate limits, and signed webhooks are all live.
Base URL
https://api.adaptlive.appAuthentication
API keys are minted from Settings → API keys inside the cockpit. The full secret is shown once at creation — store it securely. We only retain the SHA-256 hash for validation.
Every request must include the key as a Bearer token. The key itself encodes the organization it belongs to — no extra tenant header needed.
curl https://api.adaptlive.app/api/v1/schema \
-H "Authorization: Bearer ak_live_ABCDEFGHJKMNPQRSTVWXYZ0123456789"The wire format is ak_<env>_<32-char-base32> — ak_live_ for production, ak_test_ for sandbox. The secret is 160 bits of Crockford base32 entropy.
Keys carry a scope — READ, WRITE, or ADMIN — with a strict hierarchy: ADMIN ⊇ WRITE ⊇ READ. Pick the smallest scope that lets the integration do its job. Revoke any key from the same settings screen — it stops authenticating immediately.
Sandbox vs production
Every approved partner gets two orgs side-by-side: a sandbox seeded with realistic-but-fake data (keys prefixed ak_test_) and the production org tied to real numbers, real customers, and real outbound SMS (keys prefixed ak_live_).
The two surfaces are byte-identical — same endpoints, same payloads, same webhook envelope — so an integration tested against sandbox runs unchanged in production once the operator swaps the key.
To get keys: apply at /work-with-us → on approval you land in /portal with both orgs already provisioned.
Shipped endpoints
Each endpoint requires a Bearer API key and the listed scope. any means the endpoint accepts any active key — useful as a probe.
Discovery
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/schema | any | Auth probe + entity registry. Returns the org the key resolves to and the list of canonical entities the key may operate on. |
| GET | /api/v1/openapi.json | any | OpenAPI 3.1 document describing the live v1 surface. |
Canonical entities (schema registry)
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/{entity} | READ | List rows for any registered entity. Supports cursor pagination and search. |
| POST | /api/v1/{entity} | WRITE | Create a row. Supports Idempotency-Key + externalRefs for upserts from external systems. |
| GET | /api/v1/{entity}/{id} | READ | Fetch a single row by id. |
| PATCH | /api/v1/{entity}/{id} | WRITE | Partial update. Honors Idempotency-Key. |
| DELETE | /api/v1/{entity}/{id} | WRITE | Soft-delete the row. |
Work records
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/work-records | READ | List work records. Optional `?kind=` filter: JOB, APPOINTMENT, MATTER, DELIVERY, CASE. |
| POST | /api/v1/work-records | WRITE | Create a work record. Same write contract as the generic entity route. |
Communications
| Method | Path | Scope | Description |
|---|---|---|---|
| POST | /api/v1/sms | WRITE | Send an outbound SMS via the org's AdaptLive number. Accepts `to` (E.164) or `personId`. |
| GET | /api/v1/messages | READ | List SMS communication events, newest first. Optional `?direction=inbound|outbound`. |
| GET | /api/v1/voicemails | READ | List voicemails with transcripts + recording URLs. Pass `?source=calls` for the legacy CallSession shape. |
| GET | /api/v1/phone-numbers | READ | List PhoneNumber rows owned by the caller's org. |
| GET | /api/v1/calls/{id}/surface | READ | Hydrated call surface — transcript, summary, draft fields, captured facts. |
Signals & drafts
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/signals | READ | Recent SignalEvent rows. Optional `?signalKey=` resolves through SignalDefinition. |
| GET | /api/v1/drafts | READ | Post-call drafts (WorkRecord rows in the draft → approved lifecycle). Supports `?status=`. |
Facts
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/facts | READ | List facts captured across calls, messages, and forms. |
| POST | /api/v1/facts | WRITE | Create a fact directly against a subject. |
| POST | /api/v1/facts/{id}/confirm | WRITE | Mark a PROPOSED fact as CONFIRMED. Idempotent. |
| POST | /api/v1/facts/{id}/reject | WRITE | Mark a PROPOSED fact as REJECTED. |
| POST | /api/v1/facts/{id}/promote | WRITE | Promote a WorkRecord-scope fact onto a Person, Company, or Customer. |
| GET | /api/v1/fact-definitions | READ | List active FactDefinition rows for the org. |
| POST | /api/v1/fact-definitions | WRITE | Create a FactDefinition. Idempotent on (organizationId, key). |
Webhook subscriptions
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /api/v1/webhooks | READ | List webhook subscriptions for the caller's org. |
| POST | /api/v1/webhooks | WRITE | Create a subscription. Response includes the signing secret — shown once, never again. |
| DELETE | /api/v1/webhooks/{id} | WRITE | Soft-revoke a subscription. 204 on success. |
| GET | /api/v1/webhooks/{id}/deliveries | READ | Recent WebhookDelivery rows. Optional `?status=` filter and `?expand=payload`. |
| POST | /api/v1/webhooks/{id}/deliveries/{deliveryId}/replay | WRITE | Manually re-queue a delivery. Replayable from DEAD_LETTERED / FAILED states. |
cURL examples
List recent work records (filter by kind):
curl "https://api.adaptlive.app/api/v1/work-records?kind=JOB&limit=25" \
-H "Authorization: Bearer ak_test_ABCDEFGHJKMNPQRSTVWXYZ0123456789"Send an outbound SMS (with idempotency):
curl -X POST https://api.adaptlive.app/api/v1/sms \
-H "Authorization: Bearer ak_test_..." \
-H "Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-1a2b3c4d5e6f" \
-H "Content-Type: application/json" \
-d '{
"to": "+14155550123",
"body": "Confirming your 3pm appointment tomorrow."
}'Subscribe to webhook events:
curl -X POST https://api.adaptlive.app/api/v1/webhooks \
-H "Authorization: Bearer ak_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Production callback",
"url": "https://example.com/hooks/adaptlive",
"eventTypes": ["call.ended", "sms.received", "draft.approved"]
}'Confirm a proposed fact:
curl -X POST https://api.adaptlive.app/api/v1/facts/ckxxx.../confirm \
-H "Authorization: Bearer ak_live_..."Idempotency
Send an Idempotency-Key header on any POST or PATCH. We store the response for 24 hours and replay it verbatim when the same key arrives again — safe to retry through proxies, load balancers, or job runners.
If you reuse the same key with a different request body, we return 422 Unprocessable Entity with code: "idempotency_conflict". Use a fresh key per logical operation.
POST /api/v1/work-records
Authorization: Bearer ak_live_...
Idempotency-Key: 1f2e3d4c-5b6a-7c8d-9e0f-1a2b3c4d5e6f
Content-Type: application/json
{
"kind": "JOB",
"personId": "ckxxxxxxxx",
"title": "Emergency water leak"
}Pagination
Every list endpoint is cursor-paginated. Pass ?limit= (1–100, default 25) and the ?cursor=value returned in the previous page's envelope. Cursors are opaque base64 — do not parse them, just round-trip what we hand you.
{
"data": [ /* ... */ ],
"page": {
"nextCursor": "eyJpZCI6ImNreHh4eHh4eHgifQ==",
"hasMore": true
},
"requestId": "req_01HYZ..."
}Order is stable: rows are ordered by createdAt desc with id as the tiebreaker, so paging never skips or duplicates a row even when many records share a millisecond.
Rate limits
Token-bucket per organization, refilled per second:
- Read endpoints — 100 req/sec sustained, 200 burst
- Write endpoints — 30 req/sec sustained, 60 burst
When you hit the limit we return 429 Too Many Requests with Retry-After in seconds. Back off respectfully and retry — token capacity refills continuously.
Webhooks
Subscribe via the POST /api/v1/webhooks endpoint or from Settings → Webhooks. Each subscription gets a signing secret (shown once at creation). We POST a signed JSON envelope to your URL when matching events fire. Delivery is at-least-once — dedupe on eventId.
Headers we send on every delivery:
Content-Type: application/json
X-AdaptLive-Signature: t=1717009200,v1=<hmac-sha256-hex>
X-AdaptLive-Event: call.ended
X-AdaptLive-Event-Id: 01HYZ...Verify the signature by reconstructing <t>.<rawBody> and comparing your own HMAC-SHA256 to the v1 value, constant-time. Reject deliveries where the t timestamp is older than 5 minutes.
// Node.js
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(header, body, secret) {
const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
const expected = createHmac("sha256", secret)
.update(`${t}.${body}`)
.digest("hex");
return timingSafeEqual(
Buffer.from(expected, "hex"),
Buffer.from(v1, "hex"),
);
}Event types we currently emit:
| Event | Description |
|---|---|
| call.ended | A live call ended. Includes summary, transcript availability, draft fields, captured facts. |
| sms.received | An inbound SMS landed in a thread. |
| sms.sent | An outbound SMS was sent (manually or via automation). |
| voicemail.received | A caller left a voicemail. Includes transcript + recording URL. |
| call.missed | A call rang and went unanswered without a voicemail. |
| person.created | A new Person was created via call, manual entry, or API. |
| work_record.created | A new WorkRecord (appointment, job, case, ticket, etc.) was created. |
| work_record.updated | An existing WorkRecord changed status, assignment, or a tracked field. |
| fact.confirmed | A previously-PROPOSED fact was confirmed (by AI threshold or human action). |
| fact.promoted | A WorkRecord-scope fact was promoted onto a Person, Company, or Customer. |
| draft.approved | A post-call draft was approved and is ready to sync to external systems. |
| signal.fired | A signal (complaint, upsell_opportunity, etc.) fired with high confidence. |
| workflow.finished | A workflow run completed. Includes captured fields and the workflow key. |
| appointment.scheduled | A new appointment was scheduled during a call or via the API. |
| task.created | A new task or follow-up was captured. |
| note.added | A free-form note was added to a person, company, customer, or work record. |
Replays + dead letters: deliveries failing all retries land in DEAD_LETTERED and can be re-queued individually via POST /api/v1/webhooks/{id}/deliveries/{deliveryId}/replay.
Retries: 8 attempts with exponential backoff (30s → 24h). After max attempts we dead-letter the delivery; you can re-queue from the audit log or via the replay endpoint above.
Already wired: Zapier
If you want webhook + REST automation without writing code, the AdaptLive Zapier app exposes 16 triggers, 5 actions, and 2 searches against this same v1 surface. It uses real-time REST hook subscriptions (via POST /api/v1/webhooks) and falls back to polling for sample loads.
Source + trigger catalog: apps/zapier/README.md.
Next
- Canonical schema reference — the entities these endpoints operate on.
- Adapter contract — building an adapter against the same schema rather than calling the REST API directly.
- Work with us — apply for sandbox + production keys.
