Skip to main content

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.

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"
Tip

API Key authentication is recommended for all new integrations. It is simpler, easier to rotate, and does not expose your account password.

Caution

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.

ParameterTypeDefaultDescription
pageinteger0Page index. The first page is 0.
limitinteger10 or 20, per endpointPage 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/campaigns wraps 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/history and GET /partner-gateway/v1/messages/status return a plain JSON array. History still accepts page and limit: you have reached the last page when it comes back with fewer items than limit.
  • GET /partner-gateway/v1/inbox/conversations and GET /partner-gateway/v1/socials return a plain JSON array with no pagination. Narrow the inbox with its filters (unreadOnly, channelIds, dateFrom, section) and sort it with orderBy.

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​

CodeMeaningDescription
400Bad RequestThe request body or query parameters are invalid. data names the parameter and, for dates and enumerations, the accepted values.
401UnauthorizedMissing or invalid X-Api-Key, or a key that does not include the operation you called.
403ForbiddenThe request is not allowed for your account, for example a sender ID your company does not own.
404Not FoundThe 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.
409ConflictThe resource already exists, for example a webhook that is already configured.
422Unprocessable ContentSend 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.
429Too Many RequestsMessaging endpoints only: the per-account requests-per-second limit was exceeded. Honour Retry-After.
500Internal Server ErrorAn unexpected error on our side. Retry with exponential backoff and quote the X-Request-Id to support if it persists.
502Bad GatewayAn upstream channel provider returned an error.

Retry strategy​

For transient errors (429 and 5xx), implement exponential backoff with jitter:

  1. First retry: wait 1 second
  2. Second retry: wait 2 seconds
  3. Third retry: wait 4 seconds
  4. Maximum retries: 5 attempts
  5. 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​

HeaderValueDescription
Content-Typeapplication/json;charset=UTF-8Response body format
X-Request-Id16d9b2a9ca97da0d8c4c4ea2ae689017Trace identifier of the request, to quote to support
Cache-Controlno-cache, no-store, must-revalidateResponses 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 Created with the created resource.
  • Update: 200 OK with the updated resource.
  • Delete: 204 No Content for most resources. DELETE /partner-gateway/v1/contacts and DELETE /partner-gateway/v1/contacts/list answer 200 OK with true, and take the ids to delete in the ids query parameter, comma-separated, not in the body.
  • Async operations (exports): 202 Accepted with an empty body. Poll GET /partner-gateway/v1/exports until the export shows isAvailableForDownload: true, then call GET /partner-gateway/v1/exports/{exportId} for the download URL.

Timestamps​

Two formats are in use, depending on the resource:

WhereFormatExample
Delivery status and message history (sendDate, deliveryDate, readDate)ISO 8601 with offset2026-09-03T08:28:52Z
Contacts, lists, campaigns, exports, inbox (createdAt, lastMessageDate, ...) and scheduledDate on sendsyyyy-MM-dd HH:mm:ss.SSSZ2026-09-01 10:17:53.200+0000

Date query parameters​

from and to on GET /partner-gateway/v1/messages/history accept:

FormExampleRead as
Date only2026-08-27The whole UTC day: 00:00:00Z as from, 23:59:59Z as to
Date-time without offset2026-08-27T10:30:00UTC
ISO 8601 with offset2026-08-27T00:00:00%2B01:00, 2026-08-27T23:59:59ZAs 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.

Info

Subscribe to the API changelog and your account notifications to be informed of upcoming deprecations and new versions.

What's next?​