UC-019 — Analyze Message History
| Field | Value |
|---|---|
| ID | UC-019 |
| Goal | Query message history and export data for reports and audits |
| Channel | All (SMS, RCS, WhatsApp), one channel per query |
| Complexity | Intermediate |
| Estimated time | 15 minutes |
| APIs involved | GET /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
MESSAGESandEXPORTSoperations - 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://lora-api.agiletelecom.com/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": "Message delivered to handset",
"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": "ERROR",
"deliveryStatusDescription": "Undeliverable",
"sendDate": "2026-04-08T14:00:00Z",
"deliveryDate": null,
"readDate": null
}
]
:::tip 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
- One channel per query:
channelisSMS,RCSorWHATSAPP(case-insensitive). To cover several channels, run one query per channel. - Status filter: add
status=DELIVERED,ERROR,EXPIRED,SENT,RECEIVEDorUNKNOWNto keep a single delivery status. - Pagination:
pagestarts at 0 andlimitdefaults to 20. The response is a plain array: you are on the last page when it holds fewer items thanlimit. - Required range:
fromandtoare mandatory, andfrommust not be later thanto; otherwise the API answers400. - 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://lora-api.agiletelecom.com/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.
:::info 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://lora-api.agiletelecom.com/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://lora-api.agiletelecom.com/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
- Queue: the request is placed on a dedicated queue so that it does not affect the real-time API.
- Scope: the export covers all channels (SMS, RCS, WhatsApp) but only the messages sent through the API, the same ones
GET /messages/historyshows. - Storage: the file is stored behind a signed URL that expires;
expiresAttells you until when. An expired export can be regenerated withPOST /exports/{exportId}. - Format: CSV only.
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | GET /messages/history | Array of messages for the channel and date range |
| 2 | POST /messages/history/export | 202 Accepted, export queued |
| 3 | GET /exports | The export appears with isAvailableForDownload: true |
| 4 | GET /exports/{exportId} | Download URL |
Complete end-to-end example
Scenario TravelDream: monthly SMS report for March.
BASE="https://lora-api.agiletelecom.com/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://lora-api.agiletelecom.com/api/partner-gateway/v1/messages/history?channel=SMS&from=2026-04-01&to=2026-04-09&status=ERROR" \
-H "X-Api-Key: YOUR_API_KEY"
Messages sent to one recipient (GDPR audit)
The query endpoint has no recipient filter; use the export with recipient:
curl -X POST https://lora-api.agiletelecom.com/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
- UC-011 — Export Delivery Reports: Export detailed delivery reports
- UC-018 — Manage the Inbox: Manage conversations in real time
- UC-016 — Monitor Credit and Subscription: Check costs in the context of history