Skip to main content

UC-029 — Complete Campaign Report

FieldValue
IDUC-029
GoalCreate a campaign, monitor its statistics and download the complete CSV report
ChannelSMS (applicable to all channels)
Complexity⭐⭐⭐ Advanced
Estimated time25 minutes
APIs involvedPOST /api/partner-gateway/v1/campaigns, PUT /api/partner-gateway/v1/campaigns/{id}/confirm, GET /api/partner-gateway/v1/campaigns/{id}, POST /api/partner-gateway/v1/exports/delivery-reports, GET /api/partner-gateway/v1/exports, GET /api/partner-gateway/v1/exports/{exportId}

Real-world scenarios​

  • FashionOutlet — Black Friday ROI analysis: After the Black Friday campaign, the marketing team wants a detailed report with delivery rates by operator, total costs and comparison with the previous year.
  • TelcoMobile — Weekly management report: Every Monday, the communications manager generates an aggregate report of the week's campaigns for the executive team.
  • BancaAdriatica — Enterprise client delivery audit: The compliance team needs to document the delivery rate of transactional notifications for a quarterly internal audit.
Composite use case

This UC combines the flows from UC-006 — Bulk SMS Campaign and UC-011 — Export Delivery Reports into a complete end-to-end workflow.

Prerequisites​

Before you begin, make sure you have:

Test without costs

The campaign API has no simulation mode, but nothing is sent and no credit is used until you confirm the campaign (Step 2).

Complete flow​

The diagram illustrates the complete workflow: from campaign creation to CSV report download for analysis.

Step 1 — Create the campaign​

Create a new SMS campaign targeted to a contact list (destinationType: 0). With readyToSend: true the configuration is final and the campaign can be confirmed:

curl -X POST "https://api.qlara.ai/api/partner-gateway/v1/campaigns" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Black Friday 2026 - SMS Promo",
"sendingMode": "SMS",
"destinationType": 0,
"contactListIds": [3415],
"smsSender": "FashionOut",
"smsBody": "Ciao {firstName}! Black Friday FashionOutlet: -50% su tutto solo oggi! Usa il codice BF2026 su https://fashionoutlet.it/bf Rispondi STOP per opt-out.",
"scheduledDate": "2026-11-27 09:00:00.000+0100",
"readyToSend": true
}'

Response — Campaign created​

{
"id": 4512,
"name": "Black Friday 2026 - SMS Promo",
"status": "READY_TO_SEND",
"sendingMode": "SMS",
"smsSender": "FashionOut",
"destinationType": 0,
"contactListIds": [3415],
"scheduledDate": "2026-11-27 08:00:00.000+0000",
"readyToSend": true
}
Save the campaign ID

The campaign id field is needed for all subsequent steps: confirmation, monitoring and report linking.

Step 2 — Confirm the campaign send​

Nothing is sent until the campaign is confirmed. Confirming prices the campaign and reserves the amount:

curl -X PUT "https://api.qlara.ai/api/partner-gateway/v1/campaigns/4512/confirm" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Campaign confirmed​

202 Accepted, with no body: the campaign is queued and is sent at its scheduledDate.

Behind the scenes — What happens after confirmation
  1. Validation: The system verifies contact list, sender and credit.
  2. Scheduling: If the scheduledDate is in the future, the campaign stays in queue.
  3. Throttling: Sending occurs in batches (15,000 SMS in ~30-45 minutes).
  4. Credit: Charged at actual send time, not at confirmation.

Step 3 — Monitor campaign statistics​

During and after sending, check the campaign's delivery counters:

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

Response — Completed campaign statistics​

{
"id": 4512,
"name": "Black Friday 2026 - SMS Promo",
"status": "ENDED",
"sendingMode": "SMS",
"startDate": "2026-11-27 08:00:02.000+0000",
"endDate": "2026-11-27 08:38:22.000+0000",
"totalDestinations": 15420,
"totalPrice": 53970000000,
"walletKind": "EURO",
"totalSent": 15420,
"totalSuccess": 14650,
"totalFailed": 458,
"smsSent": 15420,
"smsPending": 312,
"smsSuccess": 14650,
"smsFailed": 458
}

14,650 delivered messages out of 15,420 is a 95.01% delivery rate.

Statistics polling

The counters are updated during sending. You can query the endpoint every 30-60 seconds to monitor progress. The status becomes ENDED when the sending is over; delivery reports still on their way are counted in smsPending until they arrive. GET /campaigns/stats returns similar counters for all your campaigns together, aggregated by time bucket (hour, day, week, month) and sending mode: use it for trends, not for a single campaign.

Step 4 — Export the delivery report​

Request the CSV export with the detail of every single message. Pass the campaignId alone: it is an alternative to a date range, and the export covers every channel of the campaign:

curl -X POST "https://api.qlara.ai/api/partner-gateway/v1/exports/delivery-reports" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"campaignId": 4512,
"exportFormat": "CSV"
}'

Response — Export queued​

202 Accepted, with no body: the export job is queued. The response does not carry the export ID: you find the export in the list of Step 5.

Step 5 — Download the CSV​

Poll the export list with GET /exports until the export of your campaign (detail.campaignId) shows isAvailableForDownload: true:

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/exports?page=0&limit=10" \
-H "X-Api-Key: YOUR_API_KEY"
{
"data": [
{
"id": 57,
"type": "DELIVERY_REPORT",
"detail": {
"type": "DELIVERY_REPORT",
"campaignId": 4512,
"exportFormat": "CSV"
},
"status": "COMPLETED",
"createdAt": "2026-11-28 09:00:00.000+0000",
"expiresAt": "2026-12-05 09:00:00.000+0000",
"isAvailableForDownload": true
}
],
"page": 0,
"limit": 10,
"totalCount": 1,
"totalPages": 1
}

Then get the download URL of that export with GET /exports/{exportId}:

curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/exports/57" \
-H "X-Api-Key: YOUR_API_KEY"
{
"url": "https://storage.example.com/exports/57.csv?token=f3a9c1d27b&expires=1796461200"
}
curl -o "report_blackfriday_2026.csv" \
"https://storage.example.com/exports/57.csv?token=f3a9c1d27b&expires=1796461200"
Behind the scenes — CSV structure

The CSV contains one row per message (one per part for a concatenated SMS) with columns such as DateTime, Originator, Destination, Sent type (SMS, RCS or WHATSAPP), Delivery result, SMS cost, Customer ID, Part number and Total parts. The async export is necessary for large datasets.

Expected result​

StepActionResult
1POST /campaignsCampaign created, status: "READY_TO_SEND"
2PUT /campaigns/{id}/confirm202 Accepted, delivery scheduled
3GET /campaigns/{id}status: "ENDED", totalSuccess: 14650 out of 15,420 (95.01%)
4POST /exports/delivery-reports202 Accepted, export queued
5GET /exports + GET /exports/{exportId}Download url of the CSV with 15,420 message details

Complete end-to-end example​

#!/bin/bash
API_KEY="YOUR_API_KEY"
BASE_URL="https://api.qlara.ai/api/partner-gateway/v1"

# 1. Create and confirm campaign
CMP_ID=$(curl -s -X POST "${BASE_URL}/campaigns" \
-H "X-Api-Key: ${API_KEY}" -H "Content-Type: application/json" \
-d '{"name":"Black Friday 2026","sendingMode":"SMS","destinationType":0,"contactListIds":[3415],"smsSender":"FashionOut","smsBody":"Ciao {firstName}! -50% su tutto! Codice BF2026","readyToSend":true}' | jq -r '.id')

curl -s -X PUT "${BASE_URL}/campaigns/${CMP_ID}/confirm" -H "X-Api-Key: ${API_KEY}" > /dev/null

# 2. Monitor until completion
while true; do
CMP_STATUS=$(curl -s -X GET "${BASE_URL}/campaigns/${CMP_ID}" \
-H "X-Api-Key: ${API_KEY}" | jq -r '.status')
echo "Status: ${CMP_STATUS}"
[[ "$CMP_STATUS" == "ENDED" || "$CMP_STATUS" == "ARCHIVED" ]] && break
sleep 60
done

# 3. Export, wait for the file and download it
curl -s -X POST "${BASE_URL}/exports/delivery-reports" \
-H "X-Api-Key: ${API_KEY}" -H "Content-Type: application/json" \
-d '{"campaignId":'"${CMP_ID}"',"exportFormat":"CSV"}'

EXP_ID=""
while [[ -z "$EXP_ID" ]]; do
sleep 10
EXP_ID=$(curl -s -X GET "${BASE_URL}/exports?page=0&limit=10" -H "X-Api-Key: ${API_KEY}" \
| jq -r --argjson c "$CMP_ID" '[.data[] | select(.detail.campaignId == $c and .isAvailableForDownload)][0].id // empty')
done
DL_URL=$(curl -s -X GET "${BASE_URL}/exports/${EXP_ID}" -H "X-Api-Key: ${API_KEY}" | jq -r '.url')
curl -o "report_blackfriday_2026.csv" "$DL_URL"

Variants​

Multi-channel report​

The export request has no channel filter: the export of a multi-channel campaign (for example sendingMode: "WHATSAPP_SMS") includes SMS, RCS and WhatsApp messages in the same CSV, told apart by the Sent type column.

Aggregate report by period​

For a weekly report including all campaigns, omit campaignId and specify startDateTime/endDateTime instead (format yyyy-MM-dd HH:mm:ss.SSSZ, for example 2026-11-23 00:00:00.000+0100).

Common errors​

404 Not Found — Campaign does not exist​

{ "status": "fail", "data": { "error": "Campaign not found" } }

Solution: Verify the campaign ID. Use GET /campaigns to list available campaigns.

400 Bad Request — Campaign and date range together​

{ "status": "fail", "data": { "error": "Provide either campaignId or startDateTime/endDateTime, not both" } }

Solution: campaignId and the date range are mutually exclusive: pass campaignId for a single campaign, startDateTime/endDateTime for a period.

Next steps​

References​