UC-006 — Bulk SMS Campaign to Thousands of Recipients
| Field | Value |
|---|---|
| ID | UC-006 |
| Goal | Create and send a bulk SMS campaign with cost estimation and monitoring |
| Channel | SMS |
| Complexity | Intermediate |
| Estimated time | 20 minutes |
| APIs involved | POST /api/partner-gateway/v1/campaigns, PUT /campaigns/{id}, GET /campaigns/{id}/price, PUT /campaigns/{id}/confirm, GET /campaigns/{id} |
Real-world scenarios
- ShopItalia — Black Friday: Flash promotion to 10,000 customers with a personalized discount code and a 48-hour expiration. Immediate send on Friday morning at 08:00.
- Studio Dentistico Bianchi — Weekly reminders: Every Monday the system sends a reminder of the week's appointments to all booked patients.
- AcquaLuce Energia — Bill due date: Payment due notice to all customers with unpaid invoices, with a link to the payment portal.
Prerequisites
Before you begin, make sure you have:
- Active API Key → How to get one
- Sufficient credit → Check in the Qlara Dashboard
- Contact list created and populated → See UC-007
The campaign API has no simulation mode, but nothing is sent and no credit is used until you confirm the campaign (Step 4): you can create, configure and price a draft freely.
Campaign lifecycle
The diagram illustrates the state transitions: from creation (Draft) to configuration, cost estimation, confirmation, and finally sending.
Step 1 — Create the campaign (Draft)
Create a new campaign in draft state specifying name, description, channel (sendingMode) and how recipients are chosen (destinationType: 0, from contact lists).
curl -X POST https://api.qlara.ai/api/partner-gateway/v1/campaigns \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "Black Friday 2026",
"description": "Promozione Black Friday - sconto 30% su tutto il catalogo",
"sendingMode": "SMS",
"destinationType": 0
}'
Response — Campaign created
{
"id": 1542,
"name": "Black Friday 2026",
"description": "Promozione Black Friday - sconto 30% su tutto il catalogo",
"status": "DRAFT",
"sendingMode": "SMS",
"destinationType": 0,
"readyToSend": false,
"creationDate": "2026-04-09 09:00:00.000+0000"
}
The id field is the identifier you will use in all subsequent steps. Save it to track the campaign.
Step 2 — Configure message and recipients (READY_TO_SEND)
Associate the contact list, sender, and message text with the campaign. readyToSend: true marks the configuration as final, so the campaign can be confirmed.
curl -X PUT https://api.qlara.ai/api/partner-gateway/v1/campaigns/1542 \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"sendingMode": "SMS",
"smsSender": "ShopItalia",
"smsBody": "Black Friday! Solo per te: -30% su tutto con il codice BF2026. Valido fino al 30/11. Scopri di più: https://shop.example.it/bf",
"contactListIds": [87],
"readyToSend": true
}'
Response — Campaign configured
{
"id": 1542,
"name": "Black Friday 2026",
"status": "READY_TO_SEND",
"sendingMode": "SMS",
"smsSender": "ShopItalia",
"smsBody": "Black Friday! Solo per te: -30% su tutto con il codice BF2026. Valido fino al 30/11. Scopri di più: https://shop.example.it/bf",
"destinationType": 0,
"contactListIds": [87],
"readyToSend": true,
"lastUpdateDate": "2026-04-09 09:02:00.000+0000"
}
The IDs in contactListIds must refer to already created lists. See UC-007 — Manage Contacts and Lists to create and populate lists.
Step 3 — Check the price
Check the total price before proceeding with confirmation.
curl -X GET https://api.qlara.ai/api/partner-gateway/v1/campaigns/1542/price \
-H "X-Api-Key: YOUR_API_KEY"
Response — Estimated price
{
"id": 1542,
"name": "Black Friday 2026",
"status": "READY_TO_SEND",
"sendingMode": "SMS",
"contactListIds": [87],
"totalPrice": 34408500000,
"walletKind": "EURO",
"numOfDistinctContact": 9831,
"readyToSend": true
}
numOfDistinctContact is the number of distinct recipients (9,831) and totalPrice the total price of the campaign, in the unit of the wallet named by walletKind: for EURO, hundred-millionths of a euro, so 34408500000 is €344.085.
Behind the scenes — Recipients and price
The price is computed on every call from the campaign's current configuration:
- Deduplication: The selected lists are merged and each phone number is counted once (
numOfDistinctContact). - Rate: The price depends on the
sendingMode, the number of recipients and your account's per-message rate. - SMS parts: A text within 160 GSM-7 characters (70 UCS-2) is a single SMS; a longer one is sent as several concatenated parts, up to 1530 characters.
- Always current: Every call prices the campaign again, so after changing lists, text or
sendingModejust call it again. A campaign without a valid recipient answers400.
If your credit does not cover totalPrice, confirmation will fail with 400. Top up your credit before proceeding.
Step 4 — Confirm and start sending
Confirm the campaign to start immediate sending. The request has no body.
curl -X PUT https://api.qlara.ai/api/partner-gateway/v1/campaigns/1542/confirm \
-H "X-Api-Key: YOUR_API_KEY"
Response — Campaign confirmed
202 Accepted, with no body: the campaign is queued and, since it has no scheduledDate, sending starts right away.
Variant — Scheduled send
To schedule sending at a future date, set scheduledDate (format yyyy-MM-dd HH:mm:ss.SSSZ) on the campaign before confirming it:
curl -X PUT https://api.qlara.ai/api/partner-gateway/v1/campaigns/1542 \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"sendingMode": "SMS",
"scheduledDate": "2026-11-29 08:00:00.000+0000",
"readyToSend": true
}'
Then confirm it with PUT /campaigns/1542/confirm as above: the campaign is sent at the scheduled date. Every later update of the campaign must carry scheduledDate and readyToSend: true again: an update without them removes the schedule and moves the campaign back to DRAFT.
Step 5 — Monitor progress
Check the campaign's delivery counters during and after sending.
curl -X GET "https://api.qlara.ai/api/partner-gateway/v1/campaigns/1542" \
-H "X-Api-Key: YOUR_API_KEY"
Response — Campaign completed
{
"id": 1542,
"name": "Black Friday 2026",
"status": "ENDED",
"sendingMode": "SMS",
"startDate": "2026-04-09 09:05:02.000+0000",
"endDate": "2026-04-09 09:47:00.000+0000",
"totalDestinations": 9831,
"totalPrice": 34408500000,
"walletKind": "EURO",
"totalSent": 9831,
"totalSuccess": 9542,
"totalFailed": 289,
"smsSent": 9831,
"smsPending": 0,
"smsSuccess": 9542,
"smsFailed": 289
}
Final result: 9,542 messages delivered (totalSuccess) out of 9,831 sent (totalSent), a 97.06% delivery rate. For the outcome of each single message, export the delivery reports of the campaign (see UC-029).
Common errors
400 Bad Request — Contact list not configured
{
"status": "fail",
"data": {
"contactListIds": "At least one contact list is required to confirm the campaign"
}
}
Solution: Make sure you have completed Step 2 (configuration) before checking the price and confirming.
400 Bad Request — Insufficient credit
{
"status": "fail",
"data": {
"credit": "Insufficient credit to cover the campaign totalPrice"
}
}
Solution: Top up your credit from the platform dashboard before confirming the campaign.
Expected result
| Step | Action | Result |
|---|---|---|
| 1 | POST /campaigns | Campaign in DRAFT state, id returned |
| 2 | PUT /campaigns/{id} | State READY_TO_SEND, text and list associated |
| 3 | GET /campaigns/{id}/price | totalPrice and numOfDistinctContact |
| 4 | PUT /campaigns/{id}/confirm | 202 Accepted, sending starts |
| 5 | GET /campaigns/{id} | State ENDED, delivery counters |
Next steps
- UC-007 — Manage Contacts and Lists: Create and populate contact lists for your campaigns
- UC-008 — Delivery Tracking with Webhooks: Receive real-time delivery notifications
- Campaigns Guide: Deep dive into scheduling, filters, and advanced management