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.
https://cliqtel.com/api
· Authenticate with Authorization: Bearer YOUR_API_KEY
· Get your API key →
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.
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.
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).
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.
Returns available DID numbers matching the criteria, priced at the live retail rate. This endpoint is public (no auth required).
| Parameter | Type | Required | Description |
|---|---|---|---|
| country | string | required | ISO 3166-1 alpha-2 country code (e.g. GB, NL) |
| type | string | optional | local, toll_free, mobile, or national |
Manage the numbers on your account. List/view need numbers:read; the mutations need numbers:write.
Headline usage and balance figures for a date window (defaults to the current month). Accepts from and to (YYYY-MM-DD).
Itemised, billed call records. Filter with from, to (YYYY-MM-DD), country (dialling code), and per_page. Returns Laravel pagination.
Pre-aggregated views over the same window, all requiring 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.
All require billing:read.
Paginated wallet ledger: top-ups, call/message debits, refunds, each with amount, balance_after, type, and reference_type.
| Parameter | Type | Required | Description |
|---|---|---|---|
| from | string | required | One of your SMS-enabled numbers (E.164) |
| to | string | required | Recipient in E.164 |
| body | string | required | Message text |
Paginated inbound + outbound SMS history. GET /v1/sms/messages/{id} returns a single message; GET /v1/sms/numbers lists your SMS-capable numbers.
One endpoint sends every WhatsApp message kind — the type field selects the shape. Templates can start a conversation at any time; free-form messages (text, media, location, interactive) are only allowed inside the 24-hour customer-service window.
| Parameter | Type | Required | Description |
|---|---|---|---|
| account_id | integer | required | Your WhatsApp account id (from GET /v1/whatsapp/accounts) |
| to | string | required | Recipient in E.164, e.g. +31611398058 |
| type | string | required | One of template, text, media, location, interactive |
| template | object | type=template | name, language, components (approved template) |
| body | string | type=text | Message text, up to 4096 chars |
| media | object | type=media | type (image/video/document), id, caption, filename |
| location | object | type=location | latitude, longitude, name, address |
| interactive | object | type=interactive | Reply buttons (≤3) or a list menu (see below) |
| status_callback_url | string | optional | URL to receive delivery-status webhooks for this message |
Status transitions sent → delivered → read (or failed) and are pushed to status_callback_url if set. On an empty wallet the call returns 402 with error.code = insufficient_balance.
Paginated inbound + outbound history. Filter by account_id and status. GET /v1/whatsapp/messages/{id} returns a single message with its current delivery status, cost, and any error.
Lists your connected WhatsApp accounts with id, display_name, verified_name, status, quality_rating, and messaging_limit. Use the id as account_id when sending.
Filter by account_id and status. Create with POST /v1/whatsapp/templates (whatsapp:write) and remove with DELETE /v1/whatsapp/templates/{id}.
| Parameter (create) | Type | Required | Description |
|---|---|---|---|
| account_id | integer | required | WhatsApp account id |
| name | string | required | Lowercase, digits and underscores only (^[a-z0-9_]+$) |
| category | string | required | AUTHENTICATION, UTILITY, or MARKETING |
| language | string | required | Language code, e.g. en |
| components | array | required | Template components (header/body/buttons) per Meta's format |
GET /v1/whatsapp/contact-groups (whatsapp:read) lists your groups. POST /v1/whatsapp/contact-groups/{group}/contacts adds contacts (1–5000 per call); phone numbers are normalised and de-duplicated, and opted-out contacts are skipped at send time.
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | required | Group name (create), up to 120 chars |
| contacts[] | array | add contacts | Each item: phone (E.164, required), optional name |
Sends an approved template to every sendable contact in a group. Start it with POST /v1/whatsapp/broadcasts/{id}/start; poll GET /v1/whatsapp/broadcasts/{id} for live counters. Sends are throttled to protect your quality rating.
| Parameter | Type | Required | Description |
|---|---|---|---|
| account_id | integer | required | WhatsApp account id |
| contact_group_id | integer | required | Group to send to |
| name | string | optional | Campaign name, up to 120 chars |
| template | object | required | name (approved) + language |
| variables | object | optional | Per-placeholder values; supports name personalisation |
| scheduled_at | string | optional | ISO-8601 time to send later |
| start | boolean | optional | Start immediately on create |
- 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.