adaptlive
← Developers

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.app

Authentication

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

MethodPathScopeDescription
GET/api/v1/schemaanyAuth 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.jsonanyOpenAPI 3.1 document describing the live v1 surface.

Canonical entities (schema registry)

MethodPathScopeDescription
GET/api/v1/{entity}READList rows for any registered entity. Supports cursor pagination and search.
POST/api/v1/{entity}WRITECreate a row. Supports Idempotency-Key + externalRefs for upserts from external systems.
GET/api/v1/{entity}/{id}READFetch a single row by id.
PATCH/api/v1/{entity}/{id}WRITEPartial update. Honors Idempotency-Key.
DELETE/api/v1/{entity}/{id}WRITESoft-delete the row.

Work records

MethodPathScopeDescription
GET/api/v1/work-recordsREADList work records. Optional `?kind=` filter: JOB, APPOINTMENT, MATTER, DELIVERY, CASE.
POST/api/v1/work-recordsWRITECreate a work record. Same write contract as the generic entity route.

Communications

MethodPathScopeDescription
POST/api/v1/smsWRITESend an outbound SMS via the org's AdaptLive number. Accepts `to` (E.164) or `personId`.
GET/api/v1/messagesREADList SMS communication events, newest first. Optional `?direction=inbound|outbound`.
GET/api/v1/voicemailsREADList voicemails with transcripts + recording URLs. Pass `?source=calls` for the legacy CallSession shape.
GET/api/v1/phone-numbersREADList PhoneNumber rows owned by the caller's org.
GET/api/v1/calls/{id}/surfaceREADHydrated call surface — transcript, summary, draft fields, captured facts.

Signals & drafts

MethodPathScopeDescription
GET/api/v1/signalsREADRecent SignalEvent rows. Optional `?signalKey=` resolves through SignalDefinition.
GET/api/v1/draftsREADPost-call drafts (WorkRecord rows in the draft → approved lifecycle). Supports `?status=`.

Facts

MethodPathScopeDescription
GET/api/v1/factsREADList facts captured across calls, messages, and forms.
POST/api/v1/factsWRITECreate a fact directly against a subject.
POST/api/v1/facts/{id}/confirmWRITEMark a PROPOSED fact as CONFIRMED. Idempotent.
POST/api/v1/facts/{id}/rejectWRITEMark a PROPOSED fact as REJECTED.
POST/api/v1/facts/{id}/promoteWRITEPromote a WorkRecord-scope fact onto a Person, Company, or Customer.
GET/api/v1/fact-definitionsREADList active FactDefinition rows for the org.
POST/api/v1/fact-definitionsWRITECreate a FactDefinition. Idempotent on (organizationId, key).

Webhook subscriptions

MethodPathScopeDescription
GET/api/v1/webhooksREADList webhook subscriptions for the caller's org.
POST/api/v1/webhooksWRITECreate a subscription. Response includes the signing secret — shown once, never again.
DELETE/api/v1/webhooks/{id}WRITESoft-revoke a subscription. 204 on success.
GET/api/v1/webhooks/{id}/deliveriesREADRecent WebhookDelivery rows. Optional `?status=` filter and `?expand=payload`.
POST/api/v1/webhooks/{id}/deliveries/{deliveryId}/replayWRITEManually 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:

EventDescription
call.endedA live call ended. Includes summary, transcript availability, draft fields, captured facts.
sms.receivedAn inbound SMS landed in a thread.
sms.sentAn outbound SMS was sent (manually or via automation).
voicemail.receivedA caller left a voicemail. Includes transcript + recording URL.
call.missedA call rang and went unanswered without a voicemail.
person.createdA new Person was created via call, manual entry, or API.
work_record.createdA new WorkRecord (appointment, job, case, ticket, etc.) was created.
work_record.updatedAn existing WorkRecord changed status, assignment, or a tracked field.
fact.confirmedA previously-PROPOSED fact was confirmed (by AI threshold or human action).
fact.promotedA WorkRecord-scope fact was promoted onto a Person, Company, or Customer.
draft.approvedA post-call draft was approved and is ready to sync to external systems.
signal.firedA signal (complaint, upsell_opportunity, etc.) fired with high confidence.
workflow.finishedA workflow run completed. Includes captured fields and the workflow key.
appointment.scheduledA new appointment was scheduled during a call or via the API.
task.createdA new task or follow-up was captured.
note.addedA 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

We use essential cookies to keep the app secure. Optional cookies help us improve reliability and measure campaigns. Cookie policy