Create a campaign
curl --request POST \ --url https://api.sipstack.com/api/v2/flare/campaigns \ --header 'Content-Type: application/json' \ --header 'x-api-key: <x-api-key>' \ --data '{ "name": "October promo", "message": "Hi {firstName}, 20% off this week!", "fromPhoneNumberId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "targetTags": [ "vip" ], "description": "example", "type": "immediate", "scheduledAt": "2026-04-15T12:00:00Z", "respectQuietHours": true, "quietHoursStart": "21:00", "quietHoursEnd": "09:00", "includeOptOut": true, "includeSignature": true, "dailySendLimit": 1, "steps": [ {} ], "abTestEnabled": false, "variants": [ {} ], "trackLinks": false, "smartSendEnabled": false }'import requests
url = "https://api.sipstack.com/api/v2/flare/campaigns"
payload = { "name": "October promo", "message": "Hi {firstName}, 20% off this week!", "fromPhoneNumberId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "targetTags": ["vip"], "description": "example", "type": "immediate", "scheduledAt": "2026-04-15T12:00:00Z", "respectQuietHours": True, "quietHoursStart": "21:00", "quietHoursEnd": "09:00", "includeOptOut": True, "includeSignature": True, "dailySendLimit": 1, "steps": [{}], "abTestEnabled": False, "variants": [{}], "trackLinks": False, "smartSendEnabled": False}headers = { "x-api-key": "<x-api-key>", "Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.json())const url = 'https://api.sipstack.com/api/v2/flare/campaigns';const options = { method: 'POST', headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'}, body: '{"name":"October promo","message":"Hi {firstName}, 20% off this week!","fromPhoneNumberId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","targetTags":["vip"],"description":"example","type":"immediate","scheduledAt":"2026-04-15T12:00:00Z","respectQuietHours":true,"quietHoursStart":"21:00","quietHoursEnd":"09:00","includeOptOut":true,"includeSignature":true,"dailySendLimit":1,"steps":[{}],"abTestEnabled":false,"variants":[{}],"trackLinks":false,"smartSendEnabled":false}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}import axios from 'axios';
const options = { method: 'POST', url: 'https://api.sipstack.com/api/v2/flare/campaigns', headers: {'x-api-key': '<x-api-key>', 'Content-Type': 'application/json'}, data: { name: 'October promo', message: 'Hi {firstName}, 20% off this week!', fromPhoneNumberId: '2489E9AD-2EE2-8E00-8EC9-32D5F69181C0', targetTags: ['vip'], description: 'example', type: 'immediate', scheduledAt: '2026-04-15T12:00:00Z', respectQuietHours: true, quietHoursStart: '21:00', quietHoursEnd: '09:00', includeOptOut: true, includeSignature: true, dailySendLimit: 1, steps: [{}], abTestEnabled: false, variants: [{}], trackLinks: false, smartSendEnabled: false }};
try { const { data } = await axios.request(options); console.log(data);} catch (error) { console.error(error);}Creates an A2P campaign in draft (or scheduled when scheduledAt is
set). This does not send — call the send endpoint when you’re ready.
Requires sms:send. The fromPhoneNumberId must be one of your
organization’s active numbers, an unsupported merge variable is rejected
with 422, and tier-gated options (drip / A/B / pacing / link tracking /
smart-send) return 403 if not on your plan. The response’s tags and
estimated_recipients need contacts:read as well; without it they are
null (the campaign is still created with the audience you sent).
Authorizations
Section titled “Authorizations ”Request Body required
Section titled “Request Body required ”Create an A2P campaign. targetTags is required and selects the
audience (contacts carrying any listed tag) — a create with no tags is
rejected with 400 (“At least one tag or list is required”). Opted-out
contacts are filtered at send time. Provide scheduledAt to schedule;
omit it to leave the campaign in draft until you call the send endpoint.
Only immediate and scheduled campaign types are generally available.
Higher-tier options (drip steps, A/B variants, send pacing, link tracking,
smart-send) are gated on your Flare plan and rejected with 403 if not
entitled.
object
Example
October promoMessage template. Merge variables must be from the supported set (unsupported ones are rejected with 422 UNSUPPORTED_MERGE_VARS).
Example
Hi {firstName}, 20% off this week!Public UUID of one of your organization’s active SMS numbers.
Audience — contacts carrying any of these tags.
Example
[ "vip"]drip (multi-step) requires the drip-campaigns entitlement and a steps array.
When present, the campaign is created scheduled and requires the scheduled-campaigns entitlement.
Local start of the do-not-disturb window (HH:MM). Defaults to 21:00 when omitted.
Example
21:00Local end of the do-not-disturb window (HH:MM). Defaults to 09:00 when omitted.
Example
09:00Append the standard opt-out footer to each message.
Append your organization’s message signature.
Optional per-campaign daily send cap (send-pacing tier feature). 0/omitted = no cap.
Drip steps (only when type is drip; requires the drip-campaigns entitlement).
object
Enable A/B variant testing (provide variants).
A/B message variants (tier-gated; unsupported merge vars are rejected with 422).
object
Opt in to link-click tracking (Growth+ tier-gated).
Opt in to smart-send time optimization (Growth+ tier-gated).
Responses
Section titled “ Responses ”Campaign created (the stored campaign row). Unlike the list endpoint,
the create response has no message_count — that field is only
populated by the list query’s join. Read the campaign back via
GET /api/v2/flare/campaigns/{id} for rolled-up stats.
object
A campaign row as returned by the list endpoint (the underlying record
plus a joined message_count). Snake-case fields mirror the stored row;
additional maintained columns (counters, pacing, tracking flags) may be
present.
The audience fields tags, tag_names and estimated_recipients name
your contact lists and count the contacts in them, so they need the
contacts:read scope. Without it they are null; every other field is
unchanged.
object
Delivery rate over every attempt (#6435). attempted = delivered + failed +
undelivered + sent-awaiting-receipt; queued and cancelled messages are
excluded. Rates are percentages (two decimals), null when nothing was
attempted. awaiting = sent within the last 72 hours with no delivery
receipt yet (the rate is provisional while this is above 0);
no_receipt = sent more than 72 hours ago and the carrier never confirmed
delivery — both stay in the denominator. Supersedes computing a rate from
messages_delivered / messages_sent, which ignored failures.
object
Failed + undelivered
object
Special characters (emoji, symbols, curly quotes, hidden spaces) raise the segment count of a message.
Segments per message with those characters replaced or removed.
Example
{ "data": { "status": "draft", "type": "immediate", "delivery_stats": { "attempted": 100, "delivered": 40, "failed": 55, "undelivered": 5, "failed_total": 60, "awaiting": 0, "no_receipt": 0, "delivery_rate": 40, "failure_rate": 60, "provisional": false } }, "encoding": "GSM-7", "warnings": [ { "code": "UCS2_SEGMENT_INFLATION", "characters": [ "☀", "✨" ], "segmentsWithout": 2 } ]}Missing name, message, fromPhoneNumberId, or targetTags (“At least one tag or list is required”), or the from-number isn’t one of yours.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}Missing or invalid API key.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}The key is missing the sms:send scope, the Flare API tier isn’t on your plan, or a requested option needs a higher tier.
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}The message uses an unsupported merge variable (code: UNSUPPORTED_MERGE_VARS).
Inline error shape used by the messaging API and management endpoints.
object
Example
{ "success": false, "error": "Recipient phone number (to) is required"}