Back to DevelopersReference

API Reference v1.

REST endpoints for the UnlimCall trunk and AI agents. Bearer token auth, scoped tokens, HMAC-signed webhooks. Versioned and stable — breaking changes get a new path prefix, the old version stays up for 12 months minimum.

Base URL · https://app.unlimcall.com/api/v1

Authentication

Bearer tokens, scoped.

Mint tokens from the portal at /settings/integrations. Each token has a fixed scope set — narrow it to the surface the integration needs.

ScopeDescription
read:balanceRead live account balance.
read:cdrsRead call detail records.
read:agentsList SIP lines (agents).
read:numbersList DID phone numbers on the account.
read:invoicesList historical invoices.
write:callsOriginate outbound calls via the AI agent.
write:hooksCreate and delete REST webhook subscriptions.
Send the header
Authorization: Bearer unl_live_xxxxxxxxxxxxxxxxxxxxxxx
Smoke test
curl -H "Authorization: Bearer unl_live_..." \
  https://app.unlimcall.com/api/v1/me

Tokens are revoked instantly when you delete them from the portal. Rotate on a schedule that matches your SOC profile — we don't force rotation, but we record last-used timestamps so you can spot abandoned tokens.

Endpoints

The surface area.

Seven endpoints in v1. Read endpoints first; write endpoints below. All return JSON; all are versioned at /api/v1.

GET/mescope: any valid token

Identity of the customer that owns the bearer token. Cheap call — use as a connectivity / token-validity probe.

Response · 200 OK

{
  "customerId":          "1042",
  "companyName":         "Acme Calling Co.",
  "primaryContactEmail": "[email protected]"
}

Example

curl -H "Authorization: Bearer unl_live_..." \
  https://app.unlimcall.com/api/v1/me

Error codes

CodeStatusMeaning
unauthorized401Token invalid, expired, or revoked.
suspended403Account suspended — contact support.
GET/balancescope: read:balance

Live account balance snapshot. Use to alert your finance team before credit runs out.

Response · 200 OK

{
  "balance":     42.7831,
  "currency":    "USD",
  "accountType": "prepaid",
  "creditLimit": null,
  "blocked":     false,
  "stale":       false
}

Example

curl -H "Authorization: Bearer unl_live_..." \
  https://app.unlimcall.com/api/v1/balance

Error codes

CodeStatusMeaning
unauthorized401Token invalid or missing required scope.
internal_error500Upstream snapshot fetch failed; retry.
GET/cdrsscope: read:cdrs

Call detail records over a time window. Cost figures and SIP usernames are included so you can attribute traffic back to a specific seat.

Query parameters

FieldTypeRequiredNotes
fromISO timestampnoWindow start. Default: 24h ago.
tillISO timestampnoWindow end. Default: now. Must be after `from` and within 31 days.
limitintegernoMax rows. Default 100, max 1000.

Response · 200 OK

{
  "count": 2,
  "calls": [
    {
      "id":             "1747852442.42",
      "startTime":      "2026-05-24T18:14:02.000Z",
      "duration":       81,
      "billsec":        81,
      "src":            "+14155550100",
      "dst":            "+442071838750",
      "disposition":    "ANSWERED",
      "sipUsername":    "unl_001",
      "sellPriceCents": 34,
      "currency":       "USD",
      "country":        "United Kingdom",
      "did":            null
    }
  ]
}

Example

curl -G -H "Authorization: Bearer unl_live_..." \
  --data-urlencode "from=2026-05-23T00:00:00Z" \
  --data-urlencode "till=2026-05-24T00:00:00Z" \
  --data-urlencode "limit=500" \
  https://app.unlimcall.com/api/v1/cdrs

Error codes

CodeStatusMeaning
invalid_timestamp400`from` or `till` is not parseable.
till_must_be_after_from400Window has zero or negative length.
window_too_wide400Window exceeds 31 days. Page the requests.
account_not_provisioned409Account has no trunk allocated yet.
GET/agentsscope: read:agents

List SIP lines (agents) on the account. Credentials are NOT returned — read them live from the portal.

Response · 200 OK

{
  "count": 1,
  "agents": [
    {
      "id":          "27",
      "sipUsername": "unl_001",
      "label":       "SDR seat — Berlin",
      "createdAt":   "2026-04-30T09:14:00Z"
    }
  ]
}

Example

curl -H "Authorization: Bearer unl_live_..." \
  https://app.unlimcall.com/api/v1/agents

Error codes

CodeStatusMeaning
unauthorized401Token invalid or missing required scope.
POST/callsscope: write:calls

Originate an outbound call from an AI agent to a phone number. The call rings the destination and bridges to the agent on answer.

Request body

FieldTypeRequiredNotes
aiAgentIdstring (numeric)yesID of the AI agent that should run the call. Must belong to this account.
toNumberstring (E.164)yesDestination in E.164 form, e.g. `+14155551234`.
fromNumberstring (E.164)noCaller-ID override. Validated; future-reserved (not yet forwarded to the engine).
metadataobjectnoFree-form annotations. Accepted; not yet persisted.

Response · 200 OK

{
  "callId": "f3c1e8a2-9d7f-4c5b-bd91-6e9f0a3b1c7d",
  "status": "queued"
}

Example

curl -X POST -H "Authorization: Bearer unl_live_..." \
  -H "Content-Type: application/json" \
  https://app.unlimcall.com/api/v1/calls \
  -d '{
    "aiAgentId": "27",
    "toNumber":  "+14155551234"
  }'

Error codes

CodeStatusMeaning
invalid_input400Body is not JSON, or a field failed validation.
ai_agent_not_found404No agent with that ID on this account.
ai_agent_not_provisioned409Agent has no SIP extension yet — finish setup first.
account_not_provisioned409Account has no trunk allocated yet.
dialer_required409Outbound originates require the dialer add-on.
engine_not_configured503Origination not available in this environment.
originate_failed502Upstream rejected the originate — see `detail`.
POST/hooksscope: write:hooks

Subscribe a REST webhook to a single event type. Returns the signing secret (shown ONCE).

Request body

FieldTypeRequiredNotes
eventstring (enum)yesOne of: `call.ended`, `call.transferred`, `disposition.set`, `dnc.added`, `lead.completed`.
target_urlstring (https URL)yesWhere to POST event deliveries. Must be `https://`, max 512 chars.

Response · 200 OK

{
  "id":     "8c6e3b7a-2d4f-4f9c-9e1a-7b0c5a8f2d31",
  "secret": "whsec_2VR9aBcDeFgHiJkLmNoPqRsTuVwXyZ01"
}

Example

curl -X POST -H "Authorization: Bearer unl_live_..." \
  -H "Content-Type: application/json" \
  https://app.unlimcall.com/api/v1/hooks \
  -d '{
    "event":      "call.ended",
    "target_url": "https://example.com/hooks/unlimcall"
  }'

Error codes

CodeStatusMeaning
invalid_input400Body is not JSON, `event` not in the allow-list, or `target_url` not https.
DELETE/hooks/{id}scope: write:hooks

Unsubscribe a REST hook. Soft-delete — delivery history is preserved for debugging.

Path parameters

FieldTypeRequiredNotes
idUUID v4yesThe `id` returned by `POST /hooks`.

Response · 204 No Content

(no body)

Example

curl -X DELETE -H "Authorization: Bearer unl_live_..." \
  https://app.unlimcall.com/api/v1/hooks/8c6e3b7a-2d4f-4f9c-9e1a-7b0c5a8f2d31

Error codes

CodeStatusMeaning
invalid_input400`id` is not a UUID.
not_found404Hook does not exist, is not owned by this account, or is already disabled.
Webhooks (REST hooks)

Real-time event delivery.

Subscribe via POST /hooks. Every delivery is signed with HMAC-SHA256 using the secret returned at subscription time.

  • call.ended

    Fires when a dialer or AI-agent call hangs up. Payload includes callId, contactId, phone, durationSec, dispositionCode, hangupReason, sentimentLabel, transferInitiated.

  • call.transferred

    AI agent (or live agent) initiated a transfer to a human. Use to flag hot leads in real time. Payload includes the call fields plus `transferTarget` when known.

  • disposition.set

    A call disposition was applied — by AI, by a manager inline edit, or by bulk-apply. Payload includes `terminal` and `triggersDnc` booleans plus `actor`.

  • dnc.added

    A contact was moved to Do-Not-Call (typically because the disposition triggers DNC). Mirror this into your CRM so you stop contacting them.

  • lead.completed

    A contact reached a terminal disposition. Use to move the lead out of your active pipeline.

  • Signature headerX-Unlimcall-Signature: t=<unix>,v1=<hex_sha256_hmac>
  • HMAC input`${timestamp}.${rawRequestBody}` — verify on receipt.
  • AlgorithmHMAC-SHA256 with the secret returned by POST /hooks.
  • Retry policyExponential backoff up to 24 h. 2xx = delivered, 4xx = permanent fail, 5xx + timeout = retry.
  • Auto-disableEndpoint is auto-disabled after 10 consecutive failures.
  • OrderingNo global ordering guarantee. Use `eventId` + timestamps in the payload to dedupe + order.

Receiver-side verification snippets (Node, Python, Go) live in the portal under Support → Webhooks.

End-to-end examples

Three things you'll do first.

1. List recent calls

GET /cdrs
curl -G -H "Authorization: Bearer unl_live_..." \
  --data-urlencode "from=2026-05-24T00:00:00Z" \
  --data-urlencode "limit=100" \
  https://app.unlimcall.com/api/v1/cdrs

2. Place an AI-agent call to a number

POST /calls
curl -X POST -H "Authorization: Bearer unl_live_..." \
  -H "Content-Type: application/json" \
  https://app.unlimcall.com/api/v1/calls \
  -d '{
    "aiAgentId": "27",
    "toNumber":  "+14155551234"
  }'

3. Subscribe to call.ended

POST /hooks
curl -X POST -H "Authorization: Bearer unl_live_..." \
  -H "Content-Type: application/json" \
  https://app.unlimcall.com/api/v1/hooks \
  -d '{
    "event":      "call.ended",
    "target_url": "https://example.com/hooks/unlimcall"
  }'

# 200 OK
# { "id": "...", "secret": "whsec_..." }
# Store the secret — it is shown ONCE.
Versioning

Stable contracts.

The current API is v1. Breaking changes ship under a new path prefix (/api/v2/...). The previous version is supported for at least 12 months after a new version goes GA. Additive changes (new optional fields, new endpoints) ship in-place.

Ready when you are

Pick a country.Pay in two minutes.

  • Magic-link signup
  • Cancel before commit ends
  • Lines live in ~2 min