Skip to main content

UC-019 — Analyze Message History

FieldValue
IDUC-019
GoalQuery message history and export data for reports and audits
ChannelAll (SMS, RCS, WhatsApp), one channel per query
ComplexityIntermediate
Estimated time15 minutes
APIs involvedGET /api/partner-gateway/v1/messages/history, POST /api/partner-gateway/v1/messages/history/export, GET /api/partner-gateway/v1/exports, GET /api/partner-gateway/v1/exports/{exportId}

Real-world scenarios​

  • Monthly report: The TravelDream marketing manager generates a monthly report with sending volumes by channel and delivery rate.
  • Per-channel analysis: The BrandCo team compares SMS vs WhatsApp performance to optimize the communication strategy.
  • Audit trail: The compliance officer exports the messages sent to a specific customer for a GDPR audit.

Analysis flow​

The diagram shows the interactive query flow and the asynchronous export for large datasets.

Prerequisites​

  • Active API Key with the MESSAGES and EXPORTS operations
  • At least one message sent through the API
  • For large volume exports: allow time for asynchronous processing

Step 1 — Query message history​

channel, from and to are required. A date alone covers the whole day in UTC.

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/messages/history?channel=SMS&from=2026-04-01&to=2026-04-09&page=0&limit=20" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Message history​

The response is a JSON array, one entry per message:

[
{
"customerMessageId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"channel": "SMS",
"destination": "+393471234567",
"deliveryStatus": "DELIVERED",
"deliveryStatusDescription": "delivered",
"sendDate": "2026-04-09T08:15:00Z",
"deliveryDate": "2026-04-09T08:15:03Z",
"readDate": null
},
{
"customerMessageId": "a2c4e6f8-1234-5678-9abc-def012345678",
"channel": "SMS",
"destination": "+393489876543",
"deliveryStatus": "UNDELIVERABLE",
"deliveryStatusDescription": "undeliverable",
"sendDate": "2026-04-08T14:00:00Z",
"deliveryDate": null,
"readDate": null
}
]
Accepted date formats

from and to accept a date (2026-04-01, the whole UTC day), a date-time without offset (2026-04-01T10:30:00, read as UTC) or a full ISO 8601 date-time with offset (2026-04-01T00:00:00%2B02:00, 2026-04-09T23:59:59Z). Percent-encode a + as %2B. Any other shape is answered 400 with the list of accepted formats.

Behind the scenes — Filters and pagination
  1. One channel per query: channel is SMS, RCS or WHATSAPP (case-insensitive). To cover several channels, run one query per channel.
  2. Status filter: add status with one deliveryStatus name to keep a single delivery status. The names depend on the channel (see the status table): SMS uses ACCEPTED, REJECTED, DELIVERED, EXPIRED, DELETED, UNDELIVERABLE and UNKNOWN; RCS uses DELIVERED, EXPIRED, ERROR, DISABLED, UNSUPPORTED and UNKNOWN; WhatsApp uses the RCS ones plus CONVERSATION_CLOSED. A status the channel never uses (for example ERROR on SMS) returns an empty array.
  3. Pagination: page starts at 0 and limit defaults to 20. The response is a plain array: you are on the last page when it holds fewer items than limit.
  4. Required range: from and to are mandatory, and from must not be later than to; otherwise the API answers 400.
  5. Sender and recipient filters are available on the export, not on the query.

Step 2 — Export data for reports​

For large datasets, queue an asynchronous CSV export. Dates are ISO 8601 with offset; sender and recipient are optional filters.

curl -X POST https://api.qlara.ai/api/partner-gateway/v1/messages/history/export \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"startDateTime": "2026-03-01T00:00:00+01:00",
"endDateTime": "2026-03-31T23:59:59+02:00"
}'

Response — Export queued​

202 Accepted with an empty body. The export covers every channel and only the messages sent through the API.

Asynchronous export

The file is generated in the background. Track it through the export endpoints: the list tells you when it is ready, the detail gives you the download URL.

# List your exports, newest first
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/exports?page=0&limit=10" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Export list​

{
"data": [
{
"id": 369,
"type": null,
"detail": {
"type": "DELIVERY_REPORT",
"exportFormat": "CSV",
"startDateTime": "2026-02-28T23:00:00Z",
"endDateTime": "2026-03-31T21:59:59Z",
"sendType": "API"
},
"status": null,
"createdAt": "2026-04-09 14:00:12.200+0000",
"expiresAt": "2026-04-16 14:00:12.199+0000",
"isAvailableForDownload": true
}
],
"page": 0,
"limit": 10,
"totalCount": 1,
"totalPages": 1
}

A history export appears as a DELIVERY_REPORT with sendType API. Once isAvailableForDownload is true, fetch the download URL:

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/exports/369" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Download URL​

{
"url": "https://storage.example.com/exports/369/delivery-report-2026-03.csv?X-Amz-Expires=3600&X-Amz-Signature=..."
}
Behind the scenes — Export process
  1. Queue: the request is placed on a dedicated queue so that it does not affect the real-time API.
  2. Scope: the export covers all channels (SMS, RCS, WhatsApp) but only the messages sent through the API, the same ones GET /messages/history shows.
  3. Storage: the file is stored behind a signed URL that expires; expiresAt tells you until when. An expired export can be regenerated with POST /exports/{exportId}.
  4. Format: CSV only.

Expected result​

StepActionResult
1GET /messages/historyArray of messages for the channel and date range
2POST /messages/history/export202 Accepted, export queued
3GET /exportsThe export appears with isAvailableForDownload: true
4GET /exports/{exportId}Download URL

Complete end-to-end example​

Scenario TravelDream: monthly SMS report for March.

BASE="https://api.qlara.ai/api/partner-gateway/v1"

# 1. Data preview (first 5 messages)
echo "=== March History Preview ==="
curl -s -X GET "$BASE/messages/history?channel=SMS&from=2026-03-01&to=2026-03-31&page=0&limit=5" \
-H "X-Api-Key: YOUR_API_KEY" | jq '.[] | {destination, deliveryStatus, sendDate}'

# 2. Queue the full export (202, empty body)
curl -s -o /dev/null -w "export queued: HTTP %{http_code}\n" -X POST "$BASE/messages/history/export" \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{"startDateTime": "2026-03-01T00:00:00+01:00", "endDateTime": "2026-03-31T23:59:59+02:00"}'

# 3. Wait, then take the newest export once it is ready
sleep 60
EXPORT_ID=$(curl -s -X GET "$BASE/exports?page=0&limit=1" \
-H "X-Api-Key: YOUR_API_KEY" | jq -r '.data[0] | select(.isAvailableForDownload) | .id')

# 4. Download
DOWNLOAD_URL=$(curl -s -X GET "$BASE/exports/${EXPORT_ID}" \
-H "X-Api-Key: YOUR_API_KEY" | jq -r '.url')
echo "Download: $DOWNLOAD_URL"

Variants​

Only failed messages​

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/messages/history?channel=SMS&from=2026-04-01&to=2026-04-09&status=UNDELIVERABLE" \
-H "X-Api-Key: YOUR_API_KEY"

An SMS can also fail as REJECTED or EXPIRED: run one query per status to cover them all. ERROR is an RCS and WhatsApp status, so status=ERROR on SMS always returns an empty array.

Messages sent to one recipient (GDPR audit)​

The query endpoint has no recipient filter; use the export with recipient:

curl -X POST https://api.qlara.ai/api/partner-gateway/v1/messages/history/export \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"startDateTime": "2025-01-01T00:00:00+01:00",
"endDateTime": "2026-04-09T23:59:59+02:00",
"recipient": "+393471234567"
}'

Common errors​

400 Bad Request — Missing parameters​

{
"status": "fail",
"data": "Required query params: 'channel' (RCS, WHATSAPP, SMS), 'from' and 'to' (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)"
}

Solution: pass all three parameters. channel is one of SMS, RCS, WHATSAPP.

400 Bad Request — Date in an unknown format​

{
"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"
}

Solution: use one of the formats listed in the message, and percent-encode a + in the offset as %2B.

Next steps​

References​