API Reference

The Cliqtel REST API lets you programmatically search and manage DID numbers, and pull usage records, call detail records, billing and balance data for your own reporting and account-management workflows. All responses are JSON. TLS is required on every request.

Base URL: https://cliqtel.com/api  ·  Authenticate with Authorization: Bearer YOUR_API_KEY  ·  Get your API key →
Authentication

Every request carries a Bearer token in the Authorization header. Create and revoke keys under Portal → API Keys. The full token is shown once at creation — store it securely. Tokens look like 17|aBcD… (an id, a pipe, then the secret); send the whole string.

# Example request — list this month's call records curl https://cliqtel.com/api/v1/portal/usage/calls \ -H "Authorization: Bearer 17|aBcD3fGhIjK..." \ -H "Accept: application/json"
Scopes

Keys are least-privilege. The portal offers two presets — Read-only (every *:read scope, ideal for reporting/BI integrations) and Full access (unrestricted). A key may only call endpoints covered by its scopes; anything else returns 403 insufficient_scope. The live catalog is available at GET /api/v1/portal/api-keys/scopes.

ScopeGrants
account:readProfile, organization, account settings
numbers:readList and view your numbers
numbers:writeConfigure forwarding/labels, cancel numbers
usage:readCall detail records, usage summaries, breakdowns, exports
billing:readInvoices, credit notes, wallet balance & transactions
billing:writeTop up wallet, manage payment methods
sms:read / sms:writeList / send SMS
whatsapp:read / whatsapp:writeList / send WhatsApp, manage templates
Errors & Responses

Successful responses use 2xx with a JSON body. Errors use a conventional HTTP status and a JSON envelope with an error and human-readable message. List endpoints are paginated in Laravel's standard shape (data, current_page, last_page, total).

StatusMeaning
200 / 201Success
401 unauthenticatedMissing or invalid Bearer token
403 insufficient_scopeKey lacks the scope required by this endpoint
422Validation error — see errors for per-field detail
429Rate limit exceeded — retry after the window resets
// 403 — the key is read-only but the endpoint needs a write scope { "error": "insufficient_scope", "message": "This API key is missing the required scope: sms:write.", "required_scope": "sms:write" }
Rate Limits

Reporting and account endpoints are rate-limited per authenticated user. The messaging endpoints (/v1/sms, /v1/whatsapp) allow up to 60 requests/minute. Exceeding a limit returns 429 with a Retry-After header. Design pollers to back off rather than hammer; for large exports prefer /usage/export over paging /usage/calls.

GET /v1/numbers/search Find available numbers · public

Returns available DID numbers matching the criteria, priced at the live retail rate. This endpoint is public (no auth required).

ParameterTypeRequiredDescription
countrystringrequiredISO 3166-1 alpha-2 country code (e.g. GB, NL)
typestringoptionallocal, toll_free, mobile, or national
// Response { "numbers": [ { "number": "+442079460831", "country_code": "GB", "type": "local", "monthly_price": 2.00 } ] }
List & Configure Your Numbers

Manage the numbers on your account. List/view need numbers:read; the mutations need numbers:write.

MethodPathDescription
GET/v1/portal/numbersList your numbers
GET/v1/portal/numbers/{id}View a single number
PATCH/v1/portal/numbers/{id}/forwardingSet forwarding destination
PATCH/v1/portal/numbers/{id}/labelRename / label a number
POST/v1/portal/numbers/{id}/cancelCancel a number at period end
Usage Summary
GET /v1/portal/usage/summary KPIs + balances · usage:read

Headline usage and balance figures for a date window (defaults to the current month). Accepts from and to (YYYY-MM-DD).

// Response { "minutes_this_month": 1284.5, "charges_this_month": 42.17, "total_calls": 318, "active_calls": 2, "open_holds": 0.40, "wallet_balance": 75.60, "available_balance": 75.20, "billing_mode": "prepaid", "credit_limit": 0 }
Call Detail Records
GET /v1/portal/usage/calls Paginated CDRs · usage:read

Itemised, billed call records. Filter with from, to (YYYY-MM-DD), country (dialling code), and per_page. Returns Laravel pagination.

// Response (data[] items) { "id": 90211, "call_id": "a1b2c3", "destination": "+4915112345678", "caller_id": "+442079460831", "start_time": "2026-06-01T09:14:22+00:00", "duration_seconds": 183, "billable_seconds": 183, "rate_per_minute": 0.0190, "charge": 0.06, "currency": "EUR", "billing_status": "posted" }
Usage Breakdowns & Comparison

Pre-aggregated views over the same window, all requiring usage:read:

PathReturns
/v1/portal/usage/chartDaily minutes / cost / calls (for trend charts)
/v1/portal/usage/by-didPer-number minutes, calls, cost
/v1/portal/usage/by-destinationPer destination country
/v1/portal/usage/by-trunkPer SIP trunk
/v1/portal/usage/comparisonThis month vs last month with deltas
Export Usage
GET /v1/portal/usage/export CSV / XLSX / PDF · usage:read

Streams the full call history for the window as a file. Use format = csv (default), xlsx, or pdf, plus from / to. Best path for bulk reporting — one request instead of paging.

Invoices & Credit Notes

All require billing:read.

PathReturns
/v1/portal/invoicesInvoice history (number, totals, status, has_pdf)
/v1/portal/invoices/{id}/pdfInvoice PDF
/v1/portal/credit-notesCredit note history
/v1/portal/billing/timelineUnified billing event timeline
/v1/portal/ordersOrder history
// GET /v1/portal/invoices { "invoices": [ { "invoice_number": "INV-2026-0042", "total": 12.10, "subtotal": 10.00, "tax": 2.10, "currency": "EUR", "status": "paid", "has_pdf": true } ] }
Wallet Balance
GET /v1/wallet/balance Current balance · billing:read
// Response { "balance": 75.60, "currency": "EUR" }
Wallet Transactions
GET /v1/wallet/transactions Credit/debit ledger · billing:read

Paginated wallet ledger: top-ups, call/message debits, refunds, each with amount, balance_after, type, and reference_type.

Send SMS
POST /v1/sms/messages Send a message · sms:write
ParameterTypeRequiredDescription
fromstringrequiredOne of your SMS-enabled numbers (E.164)
tostringrequiredRecipient in E.164
bodystringrequiredMessage text
// 201 Response { "data": { "id": 5521, "from": "+442079460831", "to": "+4915112345678", "status": "queued", "segments": 1, "cost": 0.0400, "currency": "EUR" } }
List SMS · GET /v1/sms/messages · sms:read

Paginated inbound + outbound SMS history. GET /v1/sms/messages/{id} returns a single message; GET /v1/sms/numbers lists your SMS-capable numbers.

Send WhatsApp

POST /v1/whatsapp/messages (whatsapp:write) sends a template or free-text message; GET /v1/whatsapp/messages and /v1/whatsapp/templates (whatsapp:read) list history and approved templates. The 24-hour customer-service window applies to free-text replies.

Roadmap
The items below are planned, not yet available. They are listed here so you can plan around them — do not build against them yet.
  • Outbound webhooks — push notifications for number.provisioned, payment.succeeded, etc. Today, poll the reporting endpoints above.
  • Official SDKs (Node.js, Python) — the API is plain REST + Bearer auth, so any HTTP client works in the meantime.
  • Number ordering via API — purchase/provisioning is currently completed in the portal checkout.