← Swiftlee home

Swiftlee REST API

v1 · JSON over HTTPS · bearer auth · HMAC-signed outbound webhooks

Base URL

https://getswiftlee.com/api/v1

White-label operator subdomains (e.g. outdesk.getswiftlee.com) accept the same endpoints — API keys are still scoped to a specific company, not an operator.

Authentication

All endpoints require a bearer token. Get a key from Settings → API keys inside the Swiftlee portal. Keys look like sl_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx.

curl https://getswiftlee.com/api/v1/me \
  -H "Authorization: Bearer sl_live_..."

The fallback header X-API-Key: sl_live_… also works for environments where Authorization headers are stripped by an upstream proxy.

Security: keys are shown ONCE on creation — we store only a SHA-256 hash. Lose it, revoke it, regenerate. Each key is scoped to a single company; cross-tenant access is impossible by construction.

Rate limits

100 requests per minute per key. 429 with Retry-After header on overage. If you need more, email support@getswiftlee.com.

Errors

Non-2xx responses share a stable shape:

{
  "error": {
    "code": "invalid_api_key",
    "message": "API key not recognized."
  }
}

Common codes: missing_api_key (401), invalid_api_key (401), api_key_revoked (401), rate_limited (429), call_not_found (404), query_failed (500).

Endpoints

GET/v1/me

Auth smoke test — returns the company the key belongs to.

{
  "company": {
    "id": "c0d4...",
    "name": "Acme Co",
    "slug": "acme-co",
    "status": "active",
    "created_at": "2026-01-12T09:00:00Z",
    "operator_id": "00000000-0000-0000-0000-000000000001"
  },
  "plan": { "slug": "growth", "name": "Growth", "included_calls": 200 },
  "api_version": "v1"
}
GET/v1/calls

List calls for the authed company, newest first. Cursor-paginated.

QUERY PARAMETERS
  • limit1–100, default 25
  • cursorISO timestamp; returns calls with started_at strictly before this
  • dispositionanswered | missed | voicemail | overflow | transferred | ai_handled
{
  "data": [
    {
      "id": "ab12...",
      "caller_e164": "+13105551234",
      "started_at": "2026-05-25T14:32:11Z",
      "ended_at": "2026-05-25T14:34:55Z",
      "disposition": "answered",
      "summary": "Caller asking about roof replacement quote.",
      "transcript": "Hi, this is...",
      "recording_available": true
    }
  ],
  "has_more": true,
  "next_cursor": "2026-05-25T14:32:11Z"
}
GET/v1/calls/:id

Full detail for one call. 404 if the call isn't in the authed company.

Webhooks

The richer integration pattern: subscribe to events at Settings → Webhooks and Swiftlee POSTs to your endpoint as events happen — no polling.

Event types: call.completed, call.qualified, call.disqualified, call.voicemail, call.no_answer, call.missed, message.captured, callback.queued, appointment.booked.

Signature: X-Swiftlee-Signature: t=<unix>,v1=<hex> — HMAC-SHA256 of ${t}.${rawBody} with your whsec_ signing secret. Reject if t is more than 5 minutes stale (replay defense).

// Node.js verification snippet
import crypto from "node:crypto";

function verifySwiftleeSignature(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(",").map((p) => p.split("=")),
  );
  const t = parts.t;
  const v1 = parts.v1;
  if (!t || !v1) return false;
  const age = Math.floor(Date.now() / 1000) - Number(t);
  if (age > 300 || age < -60) return false; // replay window
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(v1, "hex"),
  );
}

Coming soon

  • POST /v1/messages — manually capture a message
  • POST /v1/webhooks + DELETE — programmatic subscription management
  • Test-mode keys (sl_test_*) that don't mutate production data
  • Outbound dialing API + campaigns (POST /v1/calls/outbound) — requires TCPA compliance review before launch

Need something not listed? Email support@getswiftlee.com— we'll prioritize based on partner demand.