SMS campaigns
SMS campaigns endpoints of the Zanfia Workspace API, with schemas and code samples.
One-off text broadcasts to your SMS-subscribed clients, sent through your own connected SMS provider (Twilio or SMSAPI, Integrations → SMS). A campaign is composed as a draft and sent (or scheduled up to 30 days ahead) via the send route. Sending is real and irreversible, and every message is billed to you by your provider, so check the draft and its audience before you call it. The audience is all-sms-subscribed or a saved segment, and it is always narrowed to clients with a marketing-SMS consent and a phone number (so a segment previewed with POST /segments/preview can only get smaller); manage that consent in bulk with POST /clients/sms-subscription. Refusals carry a machine-readable error (not-sendable, incomplete, empty-audience, no-provider, …) with the detail in message. All routes require a Authorization: Bearer header — see Authentication.
List SMS campaigns
/sms-campaignsAuthorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Response Body
application/json
application/json
curl -X GET "https://example.com/sms-campaigns"{ "campaigns": [ { "id": "string", "name": "string", "body": "string", "optOutHint": "string", "provider": "twilio", "sender": "string", "status": "draft", "audience": { "type": "segment", "segmentId": "string" }, "recipientCount": 0, "scheduledAt": "string", "sendStartedAt": "string", "completedAt": "string", "failureReason": "string", "stats": { "sent": 0, "failed": 0, "skippedInvalidNumber": 0, "segments": 0 }, "createdAt": "string", "updatedAt": "string" } ]}{ "error": "string", "message": "string"}Create an SMS campaign draft
/sms-campaignsAuthorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Creates a DRAFT — nothing is texted. Everything beyond the name is optional at draft time.
Response Body
application/json
application/json
curl -X POST "https://example.com/sms-campaigns" \ -H "Content-Type: application/json" \ -d '{ "name": "string" }'{ "ok": true, "campaign": { "id": "string", "name": "string", "body": "string", "optOutHint": "string", "provider": "twilio", "sender": "string", "status": "draft", "audience": { "type": "segment", "segmentId": "string" }, "recipientCount": 0, "scheduledAt": "string", "sendStartedAt": "string", "completedAt": "string", "failureReason": "string", "stats": { "sent": 0, "failed": 0, "skippedInvalidNumber": 0, "segments": 0 }, "createdAt": "string", "updatedAt": "string" }}{ "error": "string", "message": "string"}Get an SMS campaign
/sms-campaigns/{campaignId}Authorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
Campaign id
Response Body
application/json
application/json
curl -X GET "https://example.com/sms-campaigns/string"{ "campaign": { "id": "string", "name": "string", "body": "string", "optOutHint": "string", "provider": "twilio", "sender": "string", "status": "draft", "audience": { "type": "segment", "segmentId": "string" }, "recipientCount": 0, "scheduledAt": "string", "sendStartedAt": "string", "completedAt": "string", "failureReason": "string", "stats": { "sent": 0, "failed": 0, "skippedInvalidNumber": 0, "segments": 0 }, "createdAt": "string", "updatedAt": "string" }}{ "error": "string", "message": "string"}Update an SMS campaign draft
/sms-campaigns/{campaignId}Authorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
Campaign id
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Drafts only — a campaign past draft is immutable except cancel.
Response Body
application/json
application/json
curl -X PATCH "https://example.com/sms-campaigns/string" \ -H "Content-Type: application/json" \ -d '{}'{ "ok": true, "campaign": { "id": "string", "name": "string", "body": "string", "optOutHint": "string", "provider": "twilio", "sender": "string", "status": "draft", "audience": { "type": "segment", "segmentId": "string" }, "recipientCount": 0, "scheduledAt": "string", "sendStartedAt": "string", "completedAt": "string", "failureReason": "string", "stats": { "sent": 0, "failed": 0, "skippedInvalidNumber": 0, "segments": 0 }, "createdAt": "string", "updatedAt": "string" }}{ "error": "string", "message": "string"}Delete an SMS campaign
/sms-campaigns/{campaignId}Authorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
Campaign id
Response Body
application/json
application/json
curl -X DELETE "https://example.com/sms-campaigns/string"{ "ok": true}{ "error": "string", "message": "string"}Send or schedule an SMS campaign
/sms-campaigns/{campaignId}/sendAuthorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
Campaign id
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
⚠️ REAL SEND: texts the campaign's resolved audience through the creator's OWN SMS provider (Twilio / SMSAPI) — every message is billed to the creator by that provider. Delivered messages cannot be recalled; the only recovery is POST /sms-campaigns/:campaignId/cancel, which stops REMAINING sends. Omit scheduledAt to send immediately.
Response Body
application/json
application/json
curl -X POST "https://example.com/sms-campaigns/string/send" \ -H "Content-Type: application/json" \ -d '{}'{ "ok": true, "campaign": { "id": "string", "name": "string", "body": "string", "optOutHint": "string", "provider": "twilio", "sender": "string", "status": "draft", "audience": { "type": "segment", "segmentId": "string" }, "recipientCount": 0, "scheduledAt": "string", "sendStartedAt": "string", "completedAt": "string", "failureReason": "string", "stats": { "sent": 0, "failed": 0, "skippedInvalidNumber": 0, "segments": 0 }, "createdAt": "string", "updatedAt": "string" }}{ "error": "string", "message": "string"}Cancel a scheduled/sending SMS campaign
/sms-campaigns/{campaignId}/cancelAuthorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
Campaign id
Response Body
application/json
application/json
curl -X POST "https://example.com/sms-campaigns/string/cancel"{ "ok": true, "campaign": { "id": "string", "name": "string", "body": "string", "optOutHint": "string", "provider": "twilio", "sender": "string", "status": "draft", "audience": { "type": "segment", "segmentId": "string" }, "recipientCount": 0, "scheduledAt": "string", "sendStartedAt": "string", "completedAt": "string", "failureReason": "string", "stats": { "sent": 0, "failed": 0, "skippedInvalidNumber": 0, "segments": 0 }, "createdAt": "string", "updatedAt": "string" }}{ "error": "string", "message": "string"}List SMS campaign recipients
/sms-campaigns/{campaignId}/recipientsAuthorization
bearerAuth API key from Dashboard → Integrations → API, MCP and CLI.
In: header
Path Parameters
Campaign id
Query Parameters
Value in
- "pending"
- "sent"
- "failed"
- "skipped-invalid-number"
1 <= value <= 20050The previous page's nextCursor (cursor is accepted as an alias).
Response Body
application/json
application/json
curl -X GET "https://example.com/sms-campaigns/string/recipients"{ "recipients": [ { "id": "string", "phoneNumber": "string", "firstName": "string", "lastName": "string", "status": "pending", "segments": 0, "statusDetails": "string", "processedAt": "string" } ], "nextCursor": "string"}{ "error": "string", "message": "string"}Was this article helpful?

