# Qlara Platform API -- Full Documentation > Unified REST API for multi-channel messaging: SMS, RCS, and WhatsApp. ## Overview The Qlara Platform is a messaging platform API that lets you send messages across SMS, RCS, and WhatsApp channels through a single integration. It provides contacts management, campaign orchestration, delivery tracking, webhook notifications, template management, and media management. --- ## Base URL ``` https://lora-api.agiletelecom.com/api ``` Every endpoint path documented here is relative to this base URL. --- ## Authentication Every request must include valid credentials. The API supports two methods: ### API Key (recommended) Pass your API key in the `X-Api-Key` header: ```bash curl -X GET "https://lora-api.agiletelecom.com/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: ```bash curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts" \ -H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=" \ -H "Accept: application/json" ``` API Key authentication is recommended for all new integrations. Never expose credentials in client-side code, public repositories, or URLs. --- ## Rate Limits Limits are applied per API key. | Plan | Rate Limit | Burst Limit | |------------|--------------------|--------------------| | Production | 1,000 requests/min | 50 requests/sec | | Trial | 100 requests/min | 10 requests/sec | When exceeded, the API responds with HTTP `429 Too Many Requests`: ```json { "status": 429, "error": "Too Many Requests", "message": "Rate limit exceeded. Please retry after 12 seconds.", "retryAfter": 12 } ``` Rate limit headers included in every response: | Header | Description | |-------------------------|------------------------------------------| | `X-RateLimit-Limit` | Maximum requests allowed per window | | `X-RateLimit-Remaining` | Requests remaining in the current window | | `X-RateLimit-Reset` | Unix timestamp when the window resets | --- ## Pagination Endpoints returning collections support offset-based pagination. | Parameter | Type | Default | Description | |-----------|---------|---------|------------------------------------| | `offset` | integer | `0` | Number of records to skip | | `limit` | integer | `20` | Number of records to return (max 100) | Example response: ```json { "data": [ ... ], "pagination": { "offset": 40, "limit": 20, "total": 1250 } } ``` Iterate by incrementing `offset` by `limit` until `offset >= total`. --- ## Error Handling ### Error response format ```json { "status": 400, "error": "Bad Request", "message": "The 'destination' field is required.", "timestamp": "2026-04-09T12:00:00Z", "path": "/api/message-server/sms/send" } ``` ### HTTP Status Codes | Code | Meaning | Description | |-------|------------------------|-----------------------------------------------------------------------------| | `400` | Bad Request | Invalid request body or query parameters. Check the `message` field. | | `401` | Unauthorized | Missing or invalid authentication credentials. | | `403` | Forbidden | API key does not have permission to access this resource. | | `404` | Not Found | Resource does not exist. Verify endpoint path and resource ID. | | `409` | Conflict | Resource already exists (e.g. webhook already configured). | | `429` | Too Many Requests | Rate limit exceeded. Wait for `Retry-After` header duration. | | `500` | Internal Server Error | Unexpected server error. Retry with exponential backoff. | ### 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: random delay of 0-500ms to each wait time Do NOT retry `400`, `401`, `403`, or `404` errors. --- ## Response Format All responses use JSON with UTF-8 encoding. Timestamps are ISO 8601 with UTC: `2026-04-09T12:34:56Z`. Common headers: - `Content-Type: application/json;charset=UTF-8` - `X-Request-Id: ` -- useful for support - `Date: ` Successful responses: - Single resource: object at top level - Collections: `data` array + `pagination` object - Create/Update: resource with `id` - Delete: HTTP `204 No Content` - Async operations: `id` + `status` to poll --- ## Versioning Qlara Platform endpoints: `/api/partner-gateway/v1/...` Channel-specific endpoints use flat paths: `/api/message-server/sms/send`, `/api/message-server/rcs/send`, `/api/message-server/whatsapp/send` Breaking changes get a new version (`v2`) with at least 6 months deprecation overlap. --- # Channel APIs -- Sending Messages --- ## SMS Universal API Modern format, one message per request, supports placeholders. ### Endpoint `POST /message-server/sms/send` ### Request Body | Field | Type | Required | Description | |--------------------|---------|----------|-------------| | `destination` | string | Yes | Recipient number in international format (e.g. `+393201234567`) | | `sender` | string | Yes | Alphanumeric (max 11 chars) or numeric sender | | `body` | string | Yes | Message text. Supports `{name}` placeholder syntax | | `campaignId` | string | No | Campaign ID for grouping and reporting (max 255 chars) | | `messageId` | string | No | Custom message ID. Auto-generated UUID if omitted | | `udhData` | string | No | UDH data in hexadecimal format for binary SMS | | `simulation` | boolean | No | If `true`, validates without sending. Default: `false` | | `enableNotification` | boolean | No | If `true`, enables delivery callbacks. Default: `true` | | `placeholders` | object | No | Key-value map for placeholder substitution. E.g. `{"nome": "Marco"}` replaces `{nome}` in the body | | `scheduledDate` | string | No | Scheduled date in `yyyy-MM-dd HH:mm:ss.SSSZ` format | | `skipRcsOverride` | boolean | No | If `true`, disables RCS override. Default: `false` | ### Response ```json { "messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "simulation": false, "results": { "sms": { "accepted": true, "unicode": false, "parts": 1, "reasons": [] } } } ``` | Field | Type | Description | |------------------------|---------|-------------| | `messageId` | string | UUID of the sent message | | `simulation` | boolean | Whether it was a dry run | | `results.sms.accepted` | boolean | Whether accepted for sending | | `results.sms.unicode` | boolean | Whether Unicode encoding was used | | `results.sms.parts` | integer | Number of SMS parts (concatenation) | | `results.sms.reasons` | array | Rejection/warning reasons | ### Curl Examples Simple SMS: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/sms/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393201234567", "sender": "MyBrand", "body": "Ciao, il tuo ordine e stato spedito!" }' ``` SMS with placeholders: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/sms/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393201234567", "sender": "MyBrand", "body": "Ciao {nome}, il tuo codice e {codice}.", "placeholders": {"nome": "Marco", "codice": "ABC123"}, "campaignId": "promo-2024-01", "enableNotification": true }' ``` Scheduled SMS: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/sms/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393201234567", "sender": "MyBrand", "body": "Promemoria: appuntamento domani alle 10:00.", "scheduledDate": "2024-12-20 09:00:00.000+0100" }' ``` --- ## SMS Legacy API Backward-compatible format, multi-recipient per request. ### Send Endpoint `POST /services/sms/send` ### Request Body | Field | Type | Required | Description | |---------------------|---------|----------|-------------| | `globalId` | string | No | Global ID of the sending session. Auto-generated if omitted | | `enableConcatenated`| boolean | No | Enable concatenation for long messages. Default: `true` | | `enableUnicode` | boolean | No | Enable Unicode encoding. Default: `true` | | `enableDelivery` | boolean | No | Enable delivery notifications. Default: `true` | | `simulation` | boolean | No | Process but do not send. Default: `false` | | `skipRcsOverride` | boolean | No | Disable automatic RCS override. Default: `false` | | `messages` | array | Yes | Array of message objects (see below) | Message object: | Field | Type | Required | Description | |----------------|--------|----------|-------------| | `destinations` | array | Yes | List of recipient numbers in international format | | `ids` | array | No | Custom IDs, one per recipient. Must match `destinations` length | | `sender` | string | Yes | SMS sender (alphanumeric max 11 chars or numeric) | | `body` | string | Yes | SMS message text | | `hexBody` | boolean| No | If true, `body` is in hexadecimal format. Default: `false` | | `udhData` | string | No | UDH in hexadecimal format | | `scheduling` | string | No | Scheduled date/time: `yyyy-MM-dd HH:mm:ss.SSSZ` | ### Response ```json { "globalId": "campaign-2025-001", "processedMessages": 1, "processedSmsParts": 2, "credit": 150.50 } ``` | Field | Type | Description | |--------------------|---------|-------------| | `globalId` | string | Session ID | | `processedMessages`| integer | Number of processed messages | | `processedSmsParts`| integer | Total SMS parts processed | | `credit` | number | Remaining credit after sending | ### Check Credit `GET /services/sms/credit` Response: `{ "credit": 150.50 }` ### Curl Example ```bash curl -X POST "https://lora-api.agiletelecom.com/api/services/sms/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "enableConcatenated": true, "enableUnicode": true, "enableDelivery": true, "messages": [ { "destinations": ["+393401234567", "+393407654321"], "sender": "MyCompany", "body": "Promo: 20% di sconto su tutti i prodotti!" } ] }' ``` --- ## RCS Send API Rich messages: text, cards, carousels with buttons and media. Supports fallback to SMS. ### Endpoint `POST /message-server/rcs/send` ### Request Body | Field | Type | Required | Description | |--------------------|---------|----------|-------------| | `destination` | string | Yes | Recipient number in international format | | `agentId` | integer | Yes | Sender RCS agent ID | | `body` | object | No* | Inline message body (mutually exclusive with `templateId`) | | `body.type` | string | Yes** | `TEXT`, `CARD`, or `CAROUSEL` | | `body.body` | object | Yes** | Content (varies by type) | | `templateId` | integer | No* | RCS template ID (mutually exclusive with `body`) | | `campaignId` | string | No | Campaign ID for grouping (max 255 chars) | | `messageId` | string | No | Custom message ID. Auto-generated UUID if omitted | | `simulation` | boolean | No | Dry run mode. Default: `false` | | `enableNotification`| boolean| No | Enable delivery/read notifications. Default: `true` | | `maxSmsParts` | integer | No | Max SMS parts for fallback. If not set, no SMS fallback | | `placeholders` | object | No | Key-value map for placeholder substitution | | `scheduledDate` | string | No | Scheduled date: `yyyy-MM-dd HH:mm:ss.SSSZ` | *One of `body` or `templateId` is required. **Required when using `body`. #### Body Types TEXT body: ```json { "type": "TEXT", "body": { "text": "Ciao! Il tuo ordine e stato confermato." } } ``` CARD body: ```json { "type": "CARD", "body": { "title": "Offerta speciale", "description": "Scopri la nostra promozione esclusiva", "mediaUrl": "https://example.com/promo.jpg", "suggestions": [ {"type": "URL", "text": "Scopri di piu", "value": "https://example.com/promo"} ] } } ``` CAROUSEL body: ```json { "type": "CAROUSEL", "body": { "cards": [ { "title": "Prodotto 1", "description": "Descrizione prodotto 1", "mediaUrl": "https://example.com/prod1.jpg", "suggestions": [ {"type": "URL", "text": "Dettagli", "value": "https://example.com/prod1"} ] }, { "title": "Prodotto 2", "description": "Descrizione prodotto 2", "mediaUrl": "https://example.com/prod2.jpg", "suggestions": [ {"type": "URL", "text": "Dettagli", "value": "https://example.com/prod2"} ] } ] } } ``` ### Response ```json { "messageId": "e76614d1-4ac1-4d94-89f0-d07f1b5a190c", "simulation": false, "results": { "rcs": { "accepted": true, "reasons": [] }, "sms": null } } ``` If RCS fails and SMS fallback is active, `results.sms` will contain the SMS result. ### Curl Examples Text message: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/rcs/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "agentId": 10, "body": { "type": "TEXT", "body": {"text": "Ciao! Il tuo ordine e stato confermato."} }, "enableNotification": true }' ``` Send with template: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/rcs/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "agentId": 10, "templateId": 42, "placeholders": {"name": "Mario", "order": "ORD-12345"}, "enableNotification": true }' ``` Send with SMS fallback: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/rcs/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "agentId": 10, "body": { "type": "TEXT", "body": {"text": "Ciao! Il tuo ordine e stato confermato."} }, "maxSmsParts": 3, "enableNotification": true }' ``` --- ## WhatsApp API Templates (Meta-approved) and free-form messages within 24h window. Content types: text, image, video, audio, document, location, sticker, reaction. Supports fallback chain: WhatsApp -> RCS -> SMS. ### Phone Numbers `GET /message-server/whatsapp/phone-numbers` -- List WhatsApp Business numbers `GET /message-server/whatsapp/phone-numbers/{id}` -- Get number details Response: ```json { "data": [ { "id": 5, "phoneNumber": "+393209998877", "displayName": "My Business", "onboardingScope": "RECEIVE_AND_SEND" } ] } ``` Use the `id` field as `phoneNumberId` in send requests. ### Send Endpoint `POST /message-server/whatsapp/send` ### Request Body | Field | Type | Required | Description | |--------------------|---------|----------|-------------| | `destination` | string | Yes | Recipient phone number in international format | | `phoneNumberId` | integer | Yes | Sender WhatsApp Business phone number ID | | `template` | object | No* | Template reference (mutually exclusive with `body`) | | `template.id` | integer | Yes** | Template ID | | `template.mediaUrl`| string | No | Media URL for template header | | `body` | object | No* | Free-form content (only within 24h window). Must contain exactly one sub-object | | `campaignId` | string | No | Campaign ID (max 255 chars) | | `messageId` | string | No | Custom message ID. Auto-generated if omitted | | `simulation` | boolean | No | Dry run. Default: `false` | | `enableNotification`| boolean| No | Enable delivery/read notifications. Default: `true` | | `placeholders` | object | No | Key-value map for placeholders. Also used for tracked links: `{"shortLinkT1": "https://..."}` | | `scheduledDate` | string | No | Scheduled date: `yyyy-MM-dd HH:mm:ss.SSSZ` | | `fallbackRcs` | object | No | RCS fallback config. If present, `fallbackSms` is required | | `fallbackRcs.agentId`| integer| Yes*** | RCS agent ID | | `fallbackRcs.templateId`| integer | No | RCS template ID (mutually exclusive with body) | | `fallbackSms` | object | No | SMS fallback config | | `fallbackSms.sender`| string | Yes**** | SMS sender | | `fallbackSms.text` | string | Yes**** | Fallback SMS text | *One of `template` or `body` is required. **Required when using `template`. ***Required when using `fallbackRcs`. ****Required when using `fallbackSms`. #### Free-form Body Types The `body` object must contain exactly one of: - `text` -- `{ "body": "Message text" }` - `image` -- `{ "url": "https://...", "caption": "..." }` (or `key` instead of `url`) - `video` -- `{ "url": "https://...", "caption": "..." }` - `audio` -- `{ "url": "https://..." }` - `document` -- `{ "url": "https://...", "filename": "file.pdf", "caption": "..." }` - `sticker` -- `{ "url": "https://..." }` - `location` -- `{ "latitude": "45.4642", "longitude": "9.1900", "name": "Store", "address": "Via Roma 1" }` - `reaction` -- `{ "messageId": "msg-id", "emoji": "thumbs-up" }` - `replyMessageId` -- string, ID of message to reply to (usable with any type) ### Response ```json { "messageId": "e76614d1-4ac1-4d94-89f0-d07f1b5a190c", "simulation": false, "results": { "whatsapp": {"accepted": true}, "rcs": null, "sms": null } } ``` ### Download Media from Inbound Messages `GET /files/{mediaKey}?expireMinutes=180` Returns a pre-signed temporary URL to download a media file received in an inbound message. ### Curl Examples Send with template: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "phoneNumberId": 5, "template": {"id": 42}, "enableNotification": true }' ``` Template + placeholder + media header: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "phoneNumberId": 5, "template": {"id": 42, "mediaUrl": "https://example.com/header-image.jpg"}, "placeholders": {"name": "Mario", "order": "ORD-12345"}, "enableNotification": true }' ``` Free-form text (within 24h window): ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "phoneNumberId": 5, "body": {"text": {"body": "Ciao! Il tuo ordine e stato spedito."}} }' ``` Send image: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "phoneNumberId": 5, "body": {"image": {"url": "https://example.com/product.jpg", "caption": "Ecco il tuo prodotto!"}} }' ``` Send document: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "phoneNumberId": 5, "body": {"document": {"url": "https://example.com/invoice.pdf", "filename": "fattura_marzo.pdf", "caption": "La tua fattura"}} }' ``` Send location: ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "phoneNumberId": 5, "body": {"location": {"latitude": "45.4642", "longitude": "9.1900", "name": "Negozio Milano Centro", "address": "Via Roma 1, 20121 Milano"}} }' ``` Send with fallback chain (WhatsApp -> RCS -> SMS): ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/send" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "destination": "+393401234567", "phoneNumberId": 5, "template": {"id": 42}, "fallbackRcs": {"agentId": 10, "templateId": 99}, "fallbackSms": {"sender": "MyCompany", "text": "Ciao! Visita https://example.com"}, "placeholders": {"name": "Mario"} }' ``` --- # Template Management --- ## RCS Templates Pre-configured messages for RCS. Three formats: TEXT, CARD, CAROUSEL. ### Endpoints | Method | Path | Description | |----------|-------------------------------------------|-------------------| | `GET` | `/message-server/rcs/templates` | List templates | | `GET` | `/message-server/rcs/templates/{id}` | Template details | | `POST` | `/message-server/rcs/templates` | Create template | | `PUT` | `/message-server/rcs/templates/{id}` | Update template | | `DELETE` | `/message-server/rcs/templates/{id}` | Delete template | ### Template Creation Fields | Field | Type | Required | Description | |---------------|--------|----------|-------------| | `name` | string | Yes | Template name | | `description` | string | No | Description | | `type` | string | Yes | `TEXT`, `CARD`, or `CAROUSEL` | | `body` | object | Yes | Content (structure varies by type) | ### TEXT Template Body | Field | Type | Required | Description | |------------------|--------|----------|-------------| | `text` | string | Yes | Message text. Supports `{variableName}` placeholders | | `suggestions` | array | No | Interactive suggestions (buttons) | | `ttlSeconds` | integer| No | Time-to-live in seconds before fallback | | `fallbackSms` | object | No | SMS fallback: `{ "sender": "...", "text": "..." }` | | `fallbackWhatsApp`| object| No | WhatsApp fallback | ### CARD Template Body | Field | Type | Required | Description | |---------------------|--------|----------|-------------| | `cardOrientation` | string | Yes | `HORIZONTAL`, `VERTICAL`, or `UNSPECIFIED` | | `thumbnailAlignment`| string | No | `LEFT`, `RIGHT`, or `UNSPECIFIED` | | `card` | object | Yes | Card with title, description, media, suggestions | | `card.title` | string | No | Card title | | `card.description` | string | No | Card description | | `card.media` | object | Yes | Media config (see Media section) | | `card.suggestions` | array | No | Card-level suggestions | | `suggestions` | array | No | Template-level suggestions | | `fallbackSms` | object | No | SMS fallback | | `fallbackWhatsApp` | object | No | WhatsApp fallback | ### CAROUSEL Template Body | Field | Type | Required | Description | |---------------|--------|----------|-------------| | `cardWidth` | string | Yes | `SMALL`, `MEDIUM`, or `UNSPECIFIED` | | `cards` | array | Yes | Array of card objects (min 1) | | `suggestions` | array | No | Template-level suggestions | | `fallbackSms` | object | No | SMS fallback | | `fallbackWhatsApp`| object | No | WhatsApp fallback | ### Media Object | Field | Type | Description | |----------------|--------|-------------| | `height` | string | `SHORT`, `MEDIUM`, `TALL`, `UNSPECIFIED` | | `fileUrl` | string | Public media URL (mutually exclusive with mediaKey) | | `mediaKey` | string | Internal media key (mutually exclusive with fileUrl) | | `thumbnailUrl` | string | Preview URL (optional) | ### Suggestion Types | Type | Description | Required fields | |----------------------|----------------------|-----------------| | `reply` | Quick reply | `text` | | `url` | Opens a link | `text`, `url.url` | | `dial` | Starts a call | `text`, `dial.phoneNumber` | | `locationCoordinates`| Shows location | `text`, `locationCoordinates.latitude`, `.longitude`, `.label` | | `locationQuery` | Searches for location| `text`, `locationQuery.query` | | `calendar` | Calendar event | `text`, `calendar.title`, `.description`, `.startTime`, `.endTime` | ### Fallback Chain - `fallbackWhatsApp`: if RCS not available, sends via WhatsApp - `fallbackSms`: if previous channel fails, sends SMS (required if fallbackWhatsApp is present) ### List Filters | Parameter | Description | |-----------|-------------| | `search` | Full-text search on name/description | | `type` | `TEXT`, `CARD`, `CAROUSEL` | | `enabled` | `0` = disabled only, `1` = enabled only | | `sortBy` | Sort field | | `sortOrder`| `asc` or `desc` | | `limit` | Items per page | | `page` | Page number (0-based) | ### Example: Create TEXT Template ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/rcs/templates" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "rcs_welcome", "description": "Welcome template", "type": "TEXT", "body": { "text": "Ciao {name}! Benvenuto nel nostro servizio.", "suggestions": [ {"type": "reply", "text": "Grazie!"}, {"type": "url", "text": "Visita il sito", "url": {"url": "https://example.com"}} ], "fallbackSms": { "sender": "AZIENDA", "text": "Ciao {name}! Benvenuto. Visita https://example.com" } } }' ``` --- ## WhatsApp Templates Meta-approved messages that can be sent at any time, even outside the 24-hour window. Required to initiate conversations. ### Endpoints | Method | Path | Description | |----------|-----------------------------------------------------------|-------------------| | `GET` | `/message-server/whatsapp/templates` | List templates | | `GET` | `/message-server/whatsapp/templates/{id}` | Template details | | `POST` | `/message-server/whatsapp/templates?phoneNumberId={id}` | Create template | | `PATCH` | `/message-server/whatsapp/templates/{id}` | Update template | | `DELETE` | `/message-server/whatsapp/templates/{id}` | Delete template | ### Template Creation Fields | Field | Type | Required | Description | |--------------------|---------|----------|-------------| | `name` | string | Yes | Template name (snake_case, lowercase, numbers, underscores only) | | `lang` | string | Yes | Language code (e.g. `it`, `en`, `es`) | | `category` | string | Yes | `MARKETING`, `UTILITY`, or `AUTHENTICATION` | | `body` | string | Yes | Body text with `{placeholderName}` placeholders | | `headerText` | string | No | Header text (exclusive with headerFormat) | | `headerFormat` | string | No | Media header: `IMAGE`, `VIDEO`, `DOCUMENT` | | `headerMediaUrl` | string | No | Media URL for header | | `footer` | string | No | Footer text | | `buttons` | array | No | Interactive buttons | | `placeholderFields`| object | No | Tracked link definition | | `trackButtonLinks` | boolean | No | Track clicks on URL buttons | ### Categories | Category | When to use | Examples | |------------------|------------|---------| | `MARKETING` | Promotions, offers, newsletters | Sales, new products, events | | `UTILITY` | Transactional communications | Order confirmation, tracking, reminders | | `AUTHENTICATION` | Identity verification | OTP, verification codes | ### Template Statuses | Status | Meaning | |------------|---------| | `APPROVED` | Approved by Meta, available for sending | | `PENDING` | Awaiting review by Meta | | `REJECTED` | Rejected by Meta | | `PAUSED` | Paused | | `DISABLED` | Disabled | ### Button Types | Field | Type | Required | Description | |---------------|--------|----------|-------------| | `type` | string | Yes | `URL`, `PHONE_NUMBER`, or `QUICK_REPLY` | | `text` | string | Yes | Displayed text | | `url` | string | URL only | URL to open | | `phoneNumber` | string | PHONE_NUMBER only | Number to call | ### Tracked Links In body: Insert `{shortLinkT1}` placeholder and define in `placeholderFields`: ```json { "body": "Ciao {firstName}, clicca qui {shortLinkT1} per la tua offerta.", "placeholderFields": { "WHATSAPP": { "shortLinkT1": "https://example.com/offerta" } } } ``` In buttons: Add `"trackButtonLinks": true` to the request. ### List Filters | Parameter | Description | |----------------|-------------| | `category` | `MARKETING`, `UTILITY`, `AUTHENTICATION` | | `status` | `APPROVED`, `PENDING`, `REJECTED`, `PAUSED`, `DISABLED` | | `phoneNumberId`| Filter by associated number | | `page` | Page number (0-based) | | `size` | Items per page | ### Updating With `PATCH /templates/{id}` you can update only the fields you want. The template returns to `PENDING` status for re-approval by Meta. ### Example: Create Template with Buttons ```bash curl -X POST "https://lora-api.agiletelecom.com/api/message-server/whatsapp/templates?phoneNumberId=5" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "marketing_welcome", "lang": "it", "category": "MARKETING", "headerText": "Welcome", "body": "Ciao {firstName} siamo contentissimi di averti tra noi", "footer": "Per info visita il sito", "buttons": [ {"type": "URL", "text": "Apri il sito", "url": "https://agiletelecom.com/"}, {"type": "PHONE_NUMBER", "text": "Chiamaci", "phoneNumber": "+39 123123123"}, {"type": "QUICK_REPLY", "text": "Voglio essere contattato"} ] }' ``` --- # Qlara Platform API Path prefix: `/api/partner-gateway/v1/` Manages: contacts, lists, campaigns, webhooks, exports, inbox, media, subscription, social profiles, API keys. --- ## Contacts ### List Contacts `GET /partner-gateway/v1/contacts` Filter by name, phone, email, gender, validity, channel support. Paginated with `offset`/`limit`. ### Create Contact `POST /partner-gateway/v1/contacts` Request body fields: - `phone` (string, required) -- Phone number in international format - `firstName` (string) -- First name - `lastName` (string) -- Last name - `fullName` (string) -- Full name - `mainEmail` (string) -- Email address - `gender` (string) -- Gender - `birthDate` (string) -- Date of birth - `city` (string) -- City - `province` (string) -- Province - `cap` (string) -- ZIP/postal code - `nation` (string) -- Nation - `fax` (string) -- Fax number - `address` (string) -- Address - `company` (string) -- Company name - `groupId` (string) -- Group ID ### Get Contact `GET /partner-gateway/v1/contacts/{id}` ### Update Contact `PUT /partner-gateway/v1/contacts/{id}` Same fields as create. ### Delete Contacts `DELETE /partner-gateway/v1/contacts` Request body: array of contact IDs to delete. ### Upload CSV/Excel `POST /partner-gateway/v1/contacts/upload` Multipart form upload. Returns parsed rows for column mapping. Confirm import: `POST /partner-gateway/v1/contacts/mapped/file` Request body: - `mappings` (array, required) -- Field mappings for each column - `listId` (integer) -- Existing list ID to add contacts to - `newList` (object) -- New list to create: `{ "name": "...", "description": "..." }` ### Upload VCard `POST /partner-gateway/v1/contacts/upload/vcard` Confirm: `POST /partner-gateway/v1/contacts/mapped/vcard` --- ## Contact Lists ### List Contact Lists `GET /partner-gateway/v1/contacts/list` Paginated. Each list includes `id`, `name`, `description`, `numContacts`, `creationDate`. ### Create Contact List `POST /partner-gateway/v1/contacts/list` Request body: - `name` (string, required) -- List name - `description` (string) -- Description ### Get Contact List `GET /partner-gateway/v1/contacts/list/{id}` ### Update Contact List `PUT /partner-gateway/v1/contacts/list/{id}` ### Delete Contact Lists `DELETE /partner-gateway/v1/contacts/list` Request body: array of list IDs. ### Add Contacts to Lists `POST /partner-gateway/v1/contacts/list/contacts` Request body: - `listIds` (array, required) -- List IDs to add contacts to - `contactIds` (array) -- Contact IDs to add (required if `allContacts` is false) - `allContacts` (boolean) -- If true, adds all contacts - `excludeIdsAllContacts` (array) -- Contact IDs to exclude when `allContacts` is true ### Remove Contacts from Lists `DELETE /partner-gateway/v1/contacts/list/contacts` Same body structure as add. ### Delete Contact from List `DELETE /partner-gateway/v1/contacts/list/contacts/{id}` ### Browse List Members `GET /partner-gateway/v1/contacts/list/{listId}/contacts` Paginated with filters for name, phone, email. Supports sorting. --- ## Campaigns ### List Campaigns `GET /partner-gateway/v1/campaigns` Paginated. Filters by status, channel, date range. Includes delivery stats. ### Create Campaign `POST /partner-gateway/v1/campaigns` Request body: | Field | Type | Description | |----------------------|---------|-------------| | `name` | string | Campaign name (max 50 chars) | | `description` | string | Description (max 350 chars) | | `sendingMode` | string | Channel: `SMS`, `RCS`, `RCS_SMS`, `WHATSAPP`, `WHATSAPP_SMS`, `WHATSAPP_RCS`, `WHATSAPP_RCS_SMS` | | `destinationType` | integer | `1` = contact lists, `2` = manual numbers | | `contactListIds` | array | List IDs for recipients (when destinationType=1) | | `destinations` | array | Manual phone numbers (when destinationType=2) | | `smsSender` | string | SMS sender name/number | | `smsBody` | string | SMS text. Supports `{{placeholder}}` syntax | | `rcsAgentId` | string | RCS agent ID (required for RCS) | | `rcsTemplateId` | integer | RCS template ID | | `whatsappPhoneNumberId` | integer | WhatsApp phone number ID (required for WhatsApp) | | `whatsappTemplateId` | integer | WhatsApp template ID | | `scheduledDate` | string | Schedule date/time | | `readyToSend` | boolean | Mark ready for confirmation | | `placeholderFields` | string | Placeholder field configuration | ### Get Campaign `GET /partner-gateway/v1/campaigns/{id}` Response includes full delivery stats: `totalDestinations`, `totalSent`, `totalSuccess`, `totalFailed`, `totalRead`, `totalFallback`, per-channel counters (`rcsSent`, `rcsSuccess`, `rcsFailed`, `rcsRead`, `smsSent`, `smsSuccess`, `smsFailed`, `waSent`, `waSuccess`, `waFailed`, `waRead`, etc.). Campaign status codes: `0` = draft, `1` = scheduled, `2` = sending, `3` = completed, `4` = error. ### Update Campaign `PUT /partner-gateway/v1/campaigns/{id}` Same fields as create (all optional). ### Delete Campaign `DELETE /partner-gateway/v1/campaigns/{id}` ### Calculate Cost `POST /partner-gateway/v1/campaigns/{id}/calculateGoal` Returns total price based on recipients and channel rates. ### Get Price `GET /partner-gateway/v1/campaigns/{id}/price` ### Confirm / Schedule `PUT /partner-gateway/v1/campaigns/{id}/confirm` Send immediately or at `scheduledDate`. ### Campaign Statistics `GET /partner-gateway/v1/campaigns/stats` Aggregated stats across campaigns. Filter by date range, channel. Returns per-time-bucket stats with `timeBucket`, `sendingMode`, `numMessageCampaigns`, delivery counters. --- ## Webhooks Configure HTTPS callback URLs to receive real-time delivery-status notifications. ### Endpoints | Method | Path | Description | |----------|--------------------------------------------|-------------| | `POST` | `/partner-gateway/v1/webhooks/delivery-status` | Configure webhook | | `GET` | `/partner-gateway/v1/webhooks/delivery-status` | Get current config | | `PUT` | `/partner-gateway/v1/webhooks/delivery-status` | Update callback URL | | `DELETE` | `/partner-gateway/v1/webhooks/delivery-status` | Revoke webhook | ### Configure Webhook ```bash curl -X POST "https://lora-api.agiletelecom.com/api/partner-gateway/v1/webhooks/delivery-status" \ -H "X-Api-Key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"callbackUrl": "https://your-server.example.com/webhooks/delivery-status"}' ``` Response: `201 Created` ```json { "companyId": 1, "callbackUrl": "https://your-server.example.com/webhooks/delivery-status" } ``` Only one webhook URL per account. If already configured, returns `409 Conflict`. Use PUT to update or DELETE to remove first. The callback URL must use HTTPS. Your server must respond with `2xx` within a reasonable timeout. Failed deliveries may be retried a limited number of times. --- ## Webhook Payloads The platform sends HTTP POST callbacks to your configured URL for delivery-status events across all channels. ### SMS DELIVERY Callback ```json { "channel": "SMS", "eventType": "DELIVERY", "messageId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "statusCode": 3, "statusDescription": "Delivered", "price": 0.035, "numPart": 1, "totalParts": 1, "timestamp": "2024-01-15T10:30:00Z" } ``` | Field | Type | Description | |-------------------|---------|-------------| | `channel` | string | `SMS` | | `eventType` | string | `DELIVERY` | | `messageId` | string | UUID of the sent message | | `statusCode` | integer | `3` = Delivered, `6` = Not Delivered | | `statusDescription`| string | Human-readable status | | `price` | number | Message cost | | `numPart` | integer | Delivered part number | | `totalParts` | integer | Total concatenated parts | | `timestamp` | string | ISO 8601 timestamp | ### RCS DELIVERY Callback ```json { "channel": "RCS", "eventType": "DELIVERY", "messageId": "uuid", "destination": "+393401234567", "statusCode": 3, "description": "delivered", "eventDate": "2025-10-16T10:42:18Z" } ``` `statusCode`: `3` = delivered, `6` = undeliverable ### RCS READ Callback ```json { "channel": "RCS", "eventType": "READ", "messageId": "uuid", "destination": "+393401234567", "eventDate": "2025-10-16T10:43:00Z" } ``` ### RCS INBOUND Callback ```json { "channel": "RCS", "eventType": "INBOUND", "messageId": "msg-id", "source": "+393471488489", "destination": "+393209998877", "receivedDate": "2025-10-31T10:59:05.099Z", "messageType": "TEXT", "text": "User reply message" } ``` `messageType`: `TEXT`, `IMAGE`, `AUDIO`, `VIDEO`. For media messages, the `mediaKey` field contains the key for downloading via `GET /api/files/{mediaKey}`. ### WhatsApp DELIVERY Callback Same structure as RCS DELIVERY with `"channel": "WHATSAPP"`. ### WhatsApp READ Callback Same structure as RCS READ with `"channel": "WHATSAPP"`. ### WhatsApp INBOUND Callback Same structure as RCS INBOUND with `"channel": "WHATSAPP"`. Media messages include `mediaKey` for download. --- ## Message Delivery Status (Polling) ### Batch Status `GET /partner-gateway/v1/messages/status` Query parameters: `batchId`, `channel`, `from`, `to`, `offset`, `limit`. ### Single Message Status `GET /partner-gateway/v1/messages/status/{customerMessageId}` Query parameters: `channel` (SMS, RCS, WHATSAPP). ### RCS Message Status `GET /partner-gateway/v1/rcs/messages/{messageId}` ### WhatsApp Message Status `GET /partner-gateway/v1/whatsapp/messages/{messageId}` WhatsApp statuses: `SENT`, `DELIVERED`, `READ`, `RECEIVED`, `ERROR`, `EXPIRED`, `UNKNOWN`. --- ## Message History ### Browse History `GET /partner-gateway/v1/messages/history` Paginated. Filter by channel, date range, status. ### Export History (CSV) `POST /partner-gateway/v1/messages/history/export` Returns an async export job. Poll via the exports workflow. --- ## Exports Asynchronous export workflow for large data sets. ### Request Export | Export type | Endpoint | |--------------------|----------| | Contacts | `POST /partner-gateway/v1/exports/contacts` | | Delivery reports | `POST /partner-gateway/v1/exports/delivery-reports` | | Message history | `POST /partner-gateway/v1/messages/history/export` | ### List Exports `GET /partner-gateway/v1/exports` Export statuses: `PENDING`, `COMPLETED`, `EXPIRED`. ### Get Download Link `GET /partner-gateway/v1/exports/{exportId}` Returns a download URL. ### Regenerate Expired Link `POST /partner-gateway/v1/exports/{exportId}` Creates a new download URL for the same export data. --- ## Inbox (Two-way Messaging) ### List Conversations `GET /partner-gateway/v1/inbox/conversations` Parameters: - `channelIds` (string) -- Comma-separated channel IDs - `dateFrom` (string) -- ISO date filter - `orderBy` (string) -- Sort field with +/- prefix (e.g. `-lastMessageDate`) - `unreadOnly` (boolean) -- Only unread conversations ### Send Reply `POST /partner-gateway/v1/inbox/conversations/reply` Sends reply on the same channel the conversation was established on. Accepted asynchronously (202). ### Get Messages `GET /partner-gateway/v1/inbox/conversations/{chatId}/messages` Parameters: - `idFrom` (integer) -- Messages with ID >= this value - `idTo` (integer) -- Messages with ID <= this value ### Mark as Read `PATCH /partner-gateway/v1/inbox/conversations/{chatId}/read` Resets unread counter. Returns 204. ### Archive Conversation `PATCH /partner-gateway/v1/inbox/conversations/{chatId}/archive` Soft operation -- no messages deleted. Returns 204. ### Unarchive Conversation `PATCH /partner-gateway/v1/inbox/conversations/{chatId}/unarchive` Returns 204. --- ## Media ### Upload Media `POST /partner-gateway/v1/media` Multipart form upload. Supports JPEG, PNG, GIF images and MP4 videos. Fields: `file` (binary, required), `name` (string), `description` (string), `folderId` (integer). ### List Media `GET /partner-gateway/v1/media` Paginated. ### Get Media `GET /partner-gateway/v1/media/{id}` ### Delete Media `DELETE /partner-gateway/v1/media/{id}` Returns 204. --- ## Subscription ### Get Active Subscription `GET /api/v1/partner-gateway/subscription` Response: ```json { "planCode": "PRO_MONTHLY", "status": "ACTIVE", "billingPeriodStart": "2025-03-01T00:00:00+01:00", "billingPeriodEnd": "2025-03-31T23:59:59+01:00", "nextRenew": "2025-04-01T00:00:00+01:00", "canceled": false, "nextPlan": null } ``` ### Get Contact Usage `GET /api/v1/partner-gateway/subscription/contacts` Returns contact usage vs. plan limits. ### Get Credit `GET /api/v1/partner-gateway/subscription/credit` Returns available messaging credit. --- ## Social Profiles Connected external platform accounts (Facebook, Instagram, LinkedIn, Google, TikTok). Profiles are established via OAuth in the web dashboard. ### List Social Profiles `GET /api/v1/partner-gateway/socials` ### Get Social Profile Detail `GET /api/v1/partner-gateway/socials/{platform}` `platform`: `facebook`, `instagram`, `linkedin`, `google`, `tiktok` (case-insensitive). Returns profile info + linked pages/sub-accounts. --- ## API Keys ### List API Keys `GET /partner-gateway/v1/authentication` Paginated. ### Create API Key `POST /partner-gateway/v1/authentication` Request body: - `username` (string) -- Username for the key - `operations` (array) -- Permitted operations Response includes the full `apiKey` string (only visible at creation time). ### Find API Key by Value `GET /partner-gateway/v1/authentication/{value}` ### Delete API Key `DELETE /partner-gateway/v1/authentication/{id}` Returns 204. --- # Channel Comparison | Feature | SMS | RCS | WhatsApp | |----------------------|------------------|------------------|-----------------------| | Rich media | No | Yes | Yes | | Template required | No | Yes | Yes (Meta-approved) | | Delivery receipts | Yes | Yes | Yes | | Read receipts | No | Yes | Yes | | Two-way messaging | Limited | Yes | Yes | | Reach | Universal | Android | WhatsApp users | | Approval process | None | Internal | Meta review | | Content types | Text only | Text, cards, carousels, media, buttons | Text, image, video, audio, document, location, sticker, reaction | ## Fallback Chain The platform supports automatic fallback: WhatsApp -> RCS -> SMS. Configure via `fallbackRcs` and `fallbackSms` fields in send requests. Sending modes for campaigns: `SMS`, `RCS`, `RCS_SMS`, `WHATSAPP`, `WHATSAPP_SMS`, `WHATSAPP_RCS`, `WHATSAPP_RCS_SMS`. --- # Error Codes Reference | Code | Meaning | When it occurs | |-------|------------------------|----------------| | `400` | Bad Request | Invalid body/params. Check `message` field for details | | `401` | Unauthorized | Missing/invalid API key or Basic Auth credentials | | `403` | Forbidden | API key lacks permission; IP not in whitelist | | `404` | Not Found | Resource doesn't exist; wrong endpoint path or ID | | `409` | Conflict | Resource already exists (e.g. duplicate webhook) | | `429` | Too Many Requests | Rate limit exceeded. Check `Retry-After` header | | `500` | Internal Server Error | Server-side issue. Retry with exponential backoff | | `502` | Bad Gateway | Upstream service temporarily unavailable | Channel-specific validation errors (SMS/RCS/WhatsApp) return JSend format: ```json { "status": "fail", "data": { "destination": "'destination' can't be blank" } } ``` WhatsApp delivery status codes: - `SENT` -- Forwarded to WhatsApp servers (single grey check) - `DELIVERED` -- Delivered to device (double grey checks) - `READ` -- Viewed by recipient (double blue checks) - `RECEIVED` -- Acknowledged but not confirmed delivered - `ERROR` -- Delivery failed (invalid number, expired window, banned account, rejected template) - `EXPIRED` -- Not delivered within time window - `UNKNOWN` -- Status not available SMS/RCS delivery status codes: - `3` = Delivered - `6` = Not Delivered / Undeliverable --- # Quick Reference -- All Endpoints ## Channel Send APIs | Method | Path | Description | |--------|------|-------------| | `POST` | `/message-server/sms/send` | Send SMS (Universal) | | `POST` | `/services/sms/send` | Send SMS (Legacy) | | `GET` | `/services/sms/credit` | Check SMS credit | | `POST` | `/message-server/rcs/send` | Send RCS message | | `POST` | `/message-server/whatsapp/send` | Send WhatsApp message | | `GET` | `/files/{mediaKey}` | Download inbound media file | ## RCS Templates | Method | Path | Description | |----------|------|-------------| | `GET` | `/message-server/rcs/templates` | List RCS templates | | `POST` | `/message-server/rcs/templates` | Create RCS template | | `GET` | `/message-server/rcs/templates/{id}` | Get RCS template | | `PUT` | `/message-server/rcs/templates/{id}` | Update RCS template | | `DELETE` | `/message-server/rcs/templates/{id}` | Delete RCS template | ## WhatsApp Phone Numbers & Templates | Method | Path | Description | |----------|------|-------------| | `GET` | `/message-server/whatsapp/phone-numbers` | List phone numbers | | `GET` | `/message-server/whatsapp/phone-numbers/{id}` | Get phone number | | `GET` | `/message-server/whatsapp/templates` | List templates | | `POST` | `/message-server/whatsapp/templates?phoneNumberId={id}` | Create template | | `GET` | `/message-server/whatsapp/templates/{id}` | Get template | | `PATCH` | `/message-server/whatsapp/templates/{id}` | Update template | | `DELETE` | `/message-server/whatsapp/templates/{id}` | Delete template | ## Qlara Platform -- Contacts | Method | Path | Description | |----------|------|-------------| | `GET` | `/partner-gateway/v1/contacts` | List contacts | | `POST` | `/partner-gateway/v1/contacts` | Create contact | | `DELETE` | `/partner-gateway/v1/contacts` | Delete contacts (bulk) | | `GET` | `/partner-gateway/v1/contacts/{id}` | Get contact | | `PUT` | `/partner-gateway/v1/contacts/{id}` | Update contact | | `POST` | `/partner-gateway/v1/contacts/upload` | Upload CSV/Excel | | `POST` | `/partner-gateway/v1/contacts/upload/vcard` | Upload VCard | ## Qlara Platform -- Contact Lists | Method | Path | Description | |----------|------|-------------| | `GET` | `/partner-gateway/v1/contacts/list` | List contact lists | | `POST` | `/partner-gateway/v1/contacts/list` | Create list | | `DELETE` | `/partner-gateway/v1/contacts/list` | Delete lists (bulk) | | `GET` | `/partner-gateway/v1/contacts/list/{id}` | Get list | | `PUT` | `/partner-gateway/v1/contacts/list/{id}` | Update list | | `POST` | `/partner-gateway/v1/contacts/list/contacts` | Add contacts to lists | | `DELETE` | `/partner-gateway/v1/contacts/list/contacts` | Remove contacts from lists | | `DELETE` | `/partner-gateway/v1/contacts/list/contacts/{id}` | Remove single contact | | `GET` | `/partner-gateway/v1/contacts/list/{listId}/contacts` | List contacts in list | ## Qlara Platform -- Campaigns | Method | Path | Description | |----------|------|-------------| | `GET` | `/partner-gateway/v1/campaigns` | List campaigns | | `POST` | `/partner-gateway/v1/campaigns` | Create campaign | | `GET` | `/partner-gateway/v1/campaigns/{id}` | Get campaign | | `PUT` | `/partner-gateway/v1/campaigns/{id}` | Update campaign | | `DELETE` | `/partner-gateway/v1/campaigns/{id}` | Delete campaign | | `POST` | `/partner-gateway/v1/campaigns/{id}/calculateGoal` | Calculate cost | | `GET` | `/partner-gateway/v1/campaigns/{id}/price` | Get price | | `PUT` | `/partner-gateway/v1/campaigns/{id}/confirm` | Confirm/schedule | | `GET` | `/partner-gateway/v1/campaigns/stats` | Campaign statistics | ## Qlara Platform -- Webhooks | Method | Path | Description | |----------|------|-------------| | `POST` | `/partner-gateway/v1/webhooks/delivery-status` | Configure webhook | | `GET` | `/partner-gateway/v1/webhooks/delivery-status` | Get webhook config | | `PUT` | `/partner-gateway/v1/webhooks/delivery-status` | Update webhook URL | | `DELETE` | `/partner-gateway/v1/webhooks/delivery-status` | Revoke webhook | ## Qlara Platform -- Exports | Method | Path | Description | |----------|------|-------------| | `GET` | `/partner-gateway/v1/exports` | List exports | | `POST` | `/partner-gateway/v1/exports/contacts` | Export contacts | | `POST` | `/partner-gateway/v1/exports/delivery-reports` | Export delivery reports | | `GET` | `/partner-gateway/v1/exports/{exportId}` | Get download link | | `POST` | `/partner-gateway/v1/exports/{exportId}` | Regenerate expired link | ## Qlara Platform -- Inbox | Method | Path | Description | |----------|------|-------------| | `GET` | `/partner-gateway/v1/inbox/conversations` | List conversations | | `POST` | `/partner-gateway/v1/inbox/conversations/reply` | Send reply | | `GET` | `/partner-gateway/v1/inbox/conversations/{chatId}/messages` | Get messages | | `PATCH` | `/partner-gateway/v1/inbox/conversations/{chatId}/read` | Mark as read | | `PATCH` | `/partner-gateway/v1/inbox/conversations/{chatId}/archive` | Archive | | `PATCH` | `/partner-gateway/v1/inbox/conversations/{chatId}/unarchive` | Unarchive | ## Qlara Platform -- Media | Method | Path | Description | |----------|------|-------------| | `POST` | `/partner-gateway/v1/media` | Upload media | | `GET` | `/partner-gateway/v1/media` | List media | | `GET` | `/partner-gateway/v1/media/{id}` | Get media | | `DELETE` | `/partner-gateway/v1/media/{id}` | Delete media | ## Qlara Platform -- Message History & Status | Method | Path | Description | |----------|------|-------------| | `GET` | `/partner-gateway/v1/messages/history` | Browse history | | `POST` | `/partner-gateway/v1/messages/history/export` | Export history (CSV) | | `GET` | `/partner-gateway/v1/messages/status` | Batch status | | `GET` | `/partner-gateway/v1/messages/status/{customerMessageId}` | Single status | | `GET` | `/partner-gateway/v1/rcs/messages/{messageId}` | RCS message status | | `GET` | `/partner-gateway/v1/whatsapp/messages/{messageId}` | WhatsApp message status | ## Qlara Platform -- Subscription | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v1/partner-gateway/subscription` | Active subscription | | `GET` | `/api/v1/partner-gateway/subscription/contacts` | Contact usage | | `GET` | `/api/v1/partner-gateway/subscription/credit` | Credit balance | ## Qlara Platform -- Social Profiles | Method | Path | Description | |--------|------|-------------| | `GET` | `/api/v1/partner-gateway/socials` | List social profiles | | `GET` | `/api/v1/partner-gateway/socials/{platform}` | Social profile detail | ## Qlara Platform -- API Keys | Method | Path | Description | |----------|------|-------------| | `GET` | `/partner-gateway/v1/authentication` | List API keys | | `POST` | `/partner-gateway/v1/authentication` | Create API key | | `GET` | `/partner-gateway/v1/authentication/{value}` | Find key by value | | `DELETE` | `/partner-gateway/v1/authentication/{id}` | Delete API key |