API Overview
This page covers the core conventions of the Qlara Platform REST API: authentication, request identification, rate limits, pagination, error handling, and response format.
Base URL
All API requests are made against the following base URL:
https://api.qlara.ai/api
Every endpoint path documented in this portal is relative to this base URL. For example, the SMS send endpoint is:
https://api.qlara.ai/api/message-server/sms/send
Authentication
Every request must include valid credentials. The API supports two authentication methods.
API Key (recommended)
Pass your API key in the X-Api-Key header:
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Accept: application/json"
Basic Auth
Pass your credentials as a Base64-encoded username:password in the Authorization header:
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts" \
-H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=" \
-H "Accept: application/json"
API Key authentication is recommended for all new integrations. It is simpler, easier to rotate, and does not expose your account password.
Never expose your API key or credentials in client-side code, public repositories, or URLs. Always send them via headers over HTTPS.
Request Identification
Every response carries an X-Request-Id header:
X-Request-Id: 16d9b2a9ca97da0d8c4c4ea2ae689017
The value is the trace identifier the platform assigned to your request, the same key that indexes every log line the request produced. Log it on your side and quote it when you contact support about a specific call. It is present on error responses too, including 401 and 500, which is when you need it most.
Rate Limits
The messaging endpoints under /api/message-server/ apply a per-account limit on requests per second, set by your subscription plan. When you exceed it, the API answers 429 Too Many Requests with an empty body and a Retry-After: 1 header: wait one second and retry.
The Qlara Platform endpoints under /api/partner-gateway/v1/ apply no rate limit at the moment and do not answer 429.
No X-RateLimit-* headers are returned by either family of endpoints. For delivery status, prefer webhooks over tight polling loops: see the Webhook guide.
Pagination
Endpoints that return collections (contacts, contact lists, campaigns, exports, media, RCS agents, WhatsApp phone numbers, message history) are page-based: page selects a page, counting from 0, and limit sets the page size.
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 0 | Page index. The first page is 0. |
limit | integer | 10 or 20, per endpoint | Page size. Where a maximum is enforced it is 1000. Check the endpoint reference. |
Example request
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/contacts?page=2&limit=20" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Accept: application/json"
Example response
{
"data": [
{
"id": 202365451,
"fullName": "Marco Rossi",
"phoneNumbers": ["+393401234567"],
"createdAt": "2026-01-15 10:30:00.000+0000"
},
{
"id": 202365452,
"fullName": "Giulia Bianchi",
"phoneNumbers": ["+393409876543"],
"createdAt": "2026-01-16 14:20:00.000+0000"
}
],
"page": 2,
"limit": 20,
"totalCount": 1250,
"totalPages": 63
}
To iterate through all records, increment page from 0 to totalPages - 1.
A few collections have a different shape:
GET /partner-gateway/v1/campaignswraps the same page object in a JSend envelope:{ "status": "success", "data": { "data": [...], "page": 0, "limit": 20, "totalCount": 12, "totalPages": 1 } }.GET /partner-gateway/v1/messages/historyandGET /partner-gateway/v1/messages/statusreturn a plain JSON array. History still acceptspageandlimit: you have reached the last page when it comes back with fewer items thanlimit.GET /partner-gateway/v1/inbox/conversationsandGET /partner-gateway/v1/socialsreturn a plain JSON array with no pagination. Narrow the inbox with its filters (unreadOnly,channelIds,dateFrom,section) and sort it withorderBy.
Error Handling
The API uses standard HTTP status codes. The Qlara Platform endpoints return a JSend body.
Error response format
A request that was refused (4xx) is a fail, and data says why. It is a string in most cases, and a list of messages when request-body validation fails:
{
"status": "fail",
"data": "Invalid 'from': '27/08/2026'. Accepted formats: yyyy-MM-dd (a whole day, UTC), yyyy-MM-ddTHH:mm:ss (UTC) or ISO-8601 with an offset such as 2025-01-15T00:00:00+01:00 or 2025-01-15T00:00:00Z"
}
A failure on our side (5xx) is an error:
{
"status": "error",
"message": "Something bad happened. Please try again!"
}
Two exceptions to this shape: a missing or invalid API key answers 401 with {"error": "Invalid API Key"} on the Qlara Platform endpoints and with an empty body on the messaging endpoints, and a 429 from the messaging endpoints has no body.
HTTP status codes
| Code | Meaning | Description |
|---|---|---|
400 | Bad Request | The request body or query parameters are invalid. data names the parameter and, for dates and enumerations, the accepted values. |
401 | Unauthorized | Missing or invalid X-Api-Key, or a key that does not include the operation you called. |
403 | Forbidden | The request is not allowed for your account, for example a sender ID your company does not own. |
404 | Not Found | The endpoint or the resource does not exist for your account. A status lookup answers 404 when the message id is unknown for the given channel. |
409 | Conflict | The resource already exists, for example a webhook that is already configured. |
422 | Unprocessable Content | Send endpoints only (POST /partner-gateway/v1/sms/messages, rcs/messages, whatsapp/messages): the messaging platform refused the message. The fail body carries the reasons. 202 is still returned when a fallback channel accepted the message. |
429 | Too Many Requests | Messaging endpoints only: the per-account requests-per-second limit was exceeded. Honour Retry-After. |
500 | Internal Server Error | An unexpected error on our side. Retry with exponential backoff and quote the X-Request-Id to support if it persists. |
502 | Bad Gateway | An upstream channel provider returned an error. |
Retry strategy
For transient errors (429 and 5xx), implement exponential backoff with jitter:
- First retry: wait 1 second
- Second retry: wait 2 seconds
- Third retry: wait 4 seconds
- Maximum retries: 5 attempts
- Add jitter: add a random delay of 0--500ms to each wait time to avoid thundering herd
Do not retry 400, 401, 403, 404, or 422 errors. These indicate a problem with your request that must be fixed before retrying: a message refused with 422 is refused again if you send it unchanged.
Response Format
All API responses use JSON with UTF-8 encoding.
Common response headers
| Header | Value | Description |
|---|---|---|
Content-Type | application/json;charset=UTF-8 | Response body format |
X-Request-Id | 16d9b2a9ca97da0d8c4c4ea2ae689017 | Trace identifier of the request, to quote to support |
Cache-Control | no-cache, no-store, must-revalidate | Responses must not be cached |
Successful responses
- Single resource: the resource object at the top level.
- Collections: the page object described under Pagination, or a plain array for the endpoints listed there.
- Create:
201 Createdwith the created resource. - Update:
200 OKwith the updated resource. - Delete:
204 No Contentfor most resources.DELETE /partner-gateway/v1/contactsandDELETE /partner-gateway/v1/contacts/listanswer200 OKwithtrue, and take the ids to delete in theidsquery parameter, comma-separated, not in the body. - Async operations (exports):
202 Acceptedwith an empty body. PollGET /partner-gateway/v1/exportsuntil the export showsisAvailableForDownload: true, then callGET /partner-gateway/v1/exports/{exportId}for the download URL.
Timestamps
Two formats are in use, depending on the resource:
| Where | Format | Example |
|---|---|---|
Delivery status and message history (sendDate, deliveryDate, readDate) | ISO 8601 with offset | 2026-09-03T08:28:52Z |
Contacts, lists, campaigns, exports, inbox (createdAt, lastMessageDate, ...) and scheduledDate on sends | yyyy-MM-dd HH:mm:ss.SSSZ | 2026-09-01 10:17:53.200+0000 |
Date query parameters
from and to on GET /partner-gateway/v1/messages/history accept:
| Form | Example | Read as |
|---|---|---|
| Date only | 2026-08-27 | The whole UTC day: 00:00:00Z as from, 23:59:59Z as to |
| Date-time without offset | 2026-08-27T10:30:00 | UTC |
| ISO 8601 with offset | 2026-08-27T00:00:00%2B01:00, 2026-08-27T23:59:59Z | As given |
Percent-encode a + in the offset as %2B: in a query string an unencoded + is decoded as a space. A value in any other shape is answered 400 with the list of accepted formats.
Delivery statuses
GET /partner-gateway/v1/messages/status and GET /partner-gateway/v1/messages/history report a normalised deliveryStatus (ACCEPTED, REJECTED, DELIVERED, EXPIRED, DELETED, UNDELIVERABLE, ERROR, DISABLED, UNSUPPORTED, CONVERSATION_CLOSED, or UNKNOWN) with a lowercase deliveryStatusDescription. The delivery-status webhook sends the same status as a numeric statusCode. The Delivery Statuses table in the API reference maps each code to its status and lists the channels that use it.
Versioning
The API version is included in the URL path:
/api/partner-gateway/v1/...
Channel-specific endpoints (SMS, RCS, WhatsApp) use a flat path without an explicit version:
/api/message-server/sms/send
/api/message-server/rcs/send
/api/message-server/whatsapp/send
When breaking changes are introduced, a new version (e.g., v2) will be published under a new path. Existing versions remain available for a deprecation period of at least 6 months, during which both versions run in parallel.
Subscribe to the API changelog and your account notifications to be informed of upcoming deprecations and new versions.
What's next?
- Quick Start -- Send your first message in 3 minutes.
- Authentication guide -- Detailed auth setup with IP whitelisting.
- API Reference -- Full endpoint documentation.
- Postman Collections -- Ready-to-use request collections.