Skip to content

Create a campaign

POST
/api/v2/flare/campaigns
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 }'

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).

Media type application/json

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
name
required
string
Example
October promo
message
required

Message template. Merge variables must be from the supported set (unsupported ones are rejected with 422 UNSUPPORTED_MERGE_VARS).

string
Example
Hi {firstName}, 20% off this week!
fromPhoneNumberId
required

Public UUID of one of your organization’s active SMS numbers.

string format: uuid
targetTags
required

Audience — contacts carrying any of these tags.

Array<string>
Example
[
"vip"
]
description
string
type

drip (multi-step) requires the drip-campaigns entitlement and a steps array.

string
default: immediate
Allowed values: immediate scheduled drip
scheduledAt

When present, the campaign is created scheduled and requires the scheduled-campaigns entitlement.

string format: date-time
respectQuietHours
boolean
default: true
quietHoursStart

Local start of the do-not-disturb window (HH:MM). Defaults to 21:00 when omitted.

string
Example
21:00
quietHoursEnd

Local end of the do-not-disturb window (HH:MM). Defaults to 09:00 when omitted.

string
Example
09:00
includeOptOut

Append the standard opt-out footer to each message.

boolean
default: true
includeSignature

Append your organization’s message signature.

boolean
default: true
dailySendLimit

Optional per-campaign daily send cap (send-pacing tier feature). 0/omitted = no cap.

integer
nullable
steps

Drip steps (only when type is drip; requires the drip-campaigns entitlement).

Array<object>
object
key
additional properties
any
abTestEnabled

Enable A/B variant testing (provide variants).

boolean
variants

A/B message variants (tier-gated; unsupported merge vars are rejected with 422).

Array<object>
object
key
additional properties
any
trackLinks

Opt in to link-click tracking (Growth+ tier-gated).

boolean
smartSendEnabled

Opt in to smart-send time optimization (Growth+ tier-gated).

boolean

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.

Media type application/json
object
success
boolean
data

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
id
string format: uuid
uuid
string format: uuid
name
string
status
string
Allowed values: draft scheduled active paused completed cancelled
type
string
Allowed values: immediate scheduled drip
message_template
string
message_count
integer
delivery_stats

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
attempted
integer
delivered
integer
failed
integer
undelivered
integer
failed_total

Failed + undelivered

integer
awaiting
integer
no_receipt
integer
delivery_rate
number
nullable
failure_rate
number
nullable
provisional
boolean
created_at
string format: date-time
key
additional properties
any
encoding
string
nullable
Allowed values: GSM-7 UCS-2
segmentsPerMessage
integer
nullable
estimatedTotalSegments
integer
nullable
estimatedDurationMinutes
integer
nullable
warnings
Array<object>
object
code

Special characters (emoji, symbols, curly quotes, hidden spaces) raise the segment count of a message.

string
Allowed values: UCS2_SEGMENT_INFLATION
characters
Array<string>
segmentsWithout

Segments per message with those characters replaced or removed.

integer
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.

Media type application/json

Inline error shape used by the messaging API and management endpoints.

object
success
boolean
error
string
Example
{
"success": false,
"error": "Recipient phone number (to) is required"
}

Missing or invalid API key.

Media type application/json

Inline error shape used by the messaging API and management endpoints.

object
success
boolean
error
string
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.

Media type application/json

Inline error shape used by the messaging API and management endpoints.

object
success
boolean
error
string
Example
{
"success": false,
"error": "Recipient phone number (to) is required"
}

The message uses an unsupported merge variable (code: UNSUPPORTED_MERGE_VARS).

Media type application/json

Inline error shape used by the messaging API and management endpoints.

object
success
boolean
error
string
Example
{
"success": false,
"error": "Recipient phone number (to) is required"
}