Intro
Endpoint: https://api.omnisend.com/api/campaigns
Manage marketing campaigns across email and SMS channels. Create campaigns, configure audience and content, then send immediately or schedule for later.
Campaign Status
| Status | Description |
|---|---|
| draft | Campaign is being prepared and can be edited |
| scheduled | Campaign is queued to send at a future time |
| started | Campaign is actively sending |
| paused | Campaign is undergoing verification — a ~60 min automated check of bounce/spam metrics before sending to the full audience |
| sent | Campaign has finished sending to all recipients |
| canceled | Campaign was explicitly canceled via the cancel endpoint |
| onHold | Campaign did not pass the automated content verification check and is held from sending. Requires review before it can be resent |
| error | Campaign encountered an error during sending |
| stopped | A/B test winner-selection phase has been halted via the stop endpoint. Can be resumed |
| expired | Campaign scheduling window has expired |
Note: Only campaigns in
draftstatus can be edited. Attempting to update a campaign in any other status returns409 Conflict.
Campaign Types
| Type | Description |
|---|---|
| regular | Standard one-time campaign |
| abTest | Sends two variants to a test audience, then sends the winner to the rest (see A/B Test Campaigns) |
| booster | Re-sends to contacts who did not open or click in a parent campaign (see Booster Campaigns) |
Channels
Each campaign targets a single message channel, set at creation and immutable.
| Channel | Description |
|---|---|
| Email campaign | |
| sms | SMS campaign |
Content
Content is channel-specific. When creating or updating a campaign, provide content under the matching channel key.
Email Content (creation)
| Field | Required | Description |
|---|---|---|
| subject | Yes | Email subject line (max 250 chars) |
| senderName | Yes | Sender display name (max 250 chars) |
| templateID | Yes | ID of an existing email template to use as the email body |
| senderEmail | No | Sender email — must belong to a verified brand domain. Omit to use brand default |
| replyToEmail | No | Reply-to address — must be a verified email |
| preheader | No | Preview text shown after the subject line (max 250 chars) |
Note: The
templateIDreferences an email template created via the Email Templates API. The template content is copied into the campaign at creation time. After creation, the campaign's email design can be edited using thecontentIDfrom the response via the Email Content API.
SMS Content (creation)
| Field | Required | Description |
|---|---|---|
| message | Yes | SMS message body. Including compliance text, must not exceed 9 SMS segments (US/CA) or equivalent |
| compliance.stopKeywordText | Yes | STOP opt-out text appended to messages for US/CA recipients (max 250 chars) |
| compliance.unsubscribeLinkText | Yes | Unsubscribe text appended for non-US/CA recipients (max 250 chars). Must include [[unsubscribe_link]] |
| imageID | No | Image ID from the Images API. Causes MMS delivery to US/CA; other regions receive SMS without image |
| isLinkShorteningEnabled | No | Auto-shorten links in the message body. Default: true |
Sending Strategies
Control when a campaign is sent using sendingSettings.strategy.
| Strategy | Description |
|---|---|
| immediate | Campaign sends as soon as the send endpoint is called. |
| scheduled | Campaign sends at the specified scheduledAt time. Must be in the future and within one year from now |
When strategy is scheduled, you can enable isTZOptimizationEnabled to deliver at the scheduled local time in each recipient's timezone.
Warning:
sendingSettingsuses full object replacement on update. When updating a scheduled campaign, provide the full object includingstrategy,scheduledAt, andisTZOptimizationEnabled— omitted fields will be reset to defaults.
Audience
Target specific subscriber segments using audience.
| Field | Description |
|---|---|
| includedSegmentIDs | Segment IDs to include. Empty array or omitted = all subscribers |
| excludedSegmentIDs | Segment IDs to exclude from the audience |
Note: Included and excluded segment lists must not overlap. Overlapping IDs will return a validation error.
Campaign Lifecycle Actions
Beyond CRUD, the API provides these lifecycle actions:
| Action | Endpoint | Description |
|---|---|---|
| Send | POST /api/campaigns/{id}/send | Start sending or schedule the campaign |
| Cancel | POST /api/campaigns/{id}/cancel | Cancel a scheduled, started, or paused campaign |
| Copy | POST /api/campaigns/{id}/copy | Create a draft copy with name prefixed "Copy of: " |
| Stop A/B | POST /api/campaigns/{id}/ab-test/stop | Halt winner selection on a started A/B test |
| Resume A/B | POST /api/campaigns/{id}/ab-test/resume | Resume winner selection on a stopped A/B test |
| Select winner | POST /api/campaigns/{id}/ab-test/winner | Manually pick the winning variant |
Note: For started email campaigns, cancellation is best-effort — messages already in flight may still be delivered.
Note: The send endpoint returns
402 Payment Requiredwhen the campaign's audience exceeds the brand's current billing tier limits (e.g., email credits or subscriber count). A plan upgrade is required to proceed.
Booster Campaigns
A booster re-sends a message to contacts who did not open or click in a parent campaign. To create one, POST a campaign with type: "booster" and boosterSettings.campaignID pointing to the parent.
The setup flow depends on whether the parent campaign has already been sent.
Flow 1: Parent is already sent
Create the booster, set sendingSettings, then call /send — exactly like a regular campaign.
POST /api/campaignswithtype: "booster",boosterSettings.campaignID,sendingSettings, and optionallycontentPOST /api/campaigns/{boosterId}/send
For email boosters, content falls back to the parent's snapshot if not provided — you only need to supply what differs (e.g. a new subject line). For SMS boosters, content.sms is required.
Flow 2: Parent is still in draft
Create the booster while the parent is being prepared. Instead of sendingSettings, provide a delay — how long after the parent sends the booster should go out. When the parent is sent, the booster is automatically scheduled.
POST /api/campaignswithtype: "booster",boosterSettings.campaignID,boosterSettings.delay, and optionallycontent- Send the parent campaign — the booster is scheduled automatically at
parent.sentAt + delay
Note: Do not provide
sendingSettingsfor a draft-parent booster — it will be rejected. The booster's schedule is system-managed until the parent is sent.
boosterSettings fields
boosterSettings fields| Field | Required | Description |
|---|---|---|
| campaignID | Yes | ID of the parent campaign to boost |
| delay | Yes (Flow 2 only) | How long after the parent sends to send the booster. Object with amount (integer) and unit ("h" or "d"). Max 240 hours |
| sendTo | Yes | nonOpeners (did not open) or nonClickers (did not click) |
Note:
boosterSettings.campaignIDand the booster'schannelare immutable after creation.
Scheduling limits
- Flow 1 —
sendingSettings.scheduledAtmust be within 10 days from now - Flow 2 —
boosterSettings.delaymust not exceed 240 hours (10 days)
Warning: For email boosters, the sender domain must be verified before sending. The send endpoint returns
409with error codesender_domain_unverifiedotherwise.
Listing boosters
GET /api/campaigns?type=booster&parentCampaignID={parentID}
Uniqueness
Each parent campaign supports at most one active booster. Creating a duplicate returns 409 Conflict. To switch channel, delete the existing booster first then create a new one — content of the deleted booster is not preserved.
Note: Newly created boosters appear with
status: "draft"in the API.
A/B Test Campaigns
An A/B test campaign splits the audience into a test group and a remainder. Two variants (A and B) are sent to the test group, and after a decision period the winning variant is sent to the rest.
A/B test campaigns are email-only. When type is abTest, content is defined per variant under abTest.variants.{a,b}.content.email — the top-level content field is omitted.
A/B test settings
| Field | Required | Description |
|---|---|---|
| testSizePercent | Yes | Percentage of audience for the test phase (10–100) |
| winningMetric | Yes (unless send-all mode) | openRate or clickRate |
| decisionTime | Yes (unless send-all mode) | How long to wait before selecting the winner. Object with amount (integer) and unit ("h" or "d") |
When testSizePercent is 100, all recipients receive a variant and no winner is sent separately ("send-all mode"). In that case winningMetric and decisionTime are not required.
Variant content
Each variant requires subject and templateID at creation. Other email fields (senderName, senderEmail, replyToEmail, preheader) are optional.
| Field | Required | Description |
|---|---|---|
| subject | Yes | Email subject line for this variant |
| templateID | Yes | Email template ID — copied into the variant at creation time |
| senderName | No | Sender display name override |
| senderEmail | No | Sender email — must belong to a verified domain |
| replyToEmail | No | Reply-to address |
| preheader | No | Preview text shown after the subject line |
Note:
templateIDis set at creation and cannot be changed via PATCH. After creation, the variant's email design is editable using thecontentIDreturned in the response via the Email Content API.
Winner selection
After the decision time elapses, the system automatically selects the winning variant based on winningMetric. Alternatively, you can manually select a winner at any time using POST /api/campaigns/{id}/ab-test/winner with the variant's id (returned in abTest.variants.a.id / abTest.variants.b.id).
The result is available in abTest.result:
| Field | Description |
|---|---|
| winnerVariantID | Campaign ID of the winning variant |
| isManuallySelected | Whether the winner was manually picked |
| selectedAt | Timestamp of winner selection |
Stopping and resuming
While an A/B test is in started status, you can halt automatic winner selection with POST /api/campaigns/{id}/ab-test/stop (moves to stopped status). Resume with POST /api/campaigns/{id}/ab-test/resume.
Warning:
abTestuses full replacement semantics on update. When patching A/B test settings or variant content, provide the fullabTestblock — omitted fields will be reset.
Example: Create an email campaign
curl --request POST \
--url https://api.omnisend.com/api/campaigns \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"name": "Summer Sale Announcement",
"type": "regular",
"channel": "email",
"language": "en_US",
"content": {
"email": {
"subject": "Summer Sale — Up to 50% Off!",
"senderName": "My Store",
"senderEmail": "[email protected]",
"preheader": "Shop our biggest sale of the season",
"templateID": "000000000000000000000001"
}
},
"audience": {
"includedSegmentIDs": ["111111111111111111111111"],
"excludedSegmentIDs": ["222222222222222222222222"]
},
"sendingSettings": {
"strategy": "scheduled",
"scheduledAt": "2026-06-15T10:00:00Z",
"isTZOptimizationEnabled": true
}
}'Creates a scheduled email campaign targeting a specific segment, with timezone optimization enabled.
Example: Update campaign email content
curl --request PATCH \
--url https://api.omnisend.com/api/campaigns/000000000000000000000001 \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"content": {
"email": {
"subject": "Updated Subject Line"
}
}
}'Email content fields are partially updated — only the fields you include will change.
Example: Create an email booster (sent parent)
curl --request POST \
--url https://api.omnisend.com/api/campaigns \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"name": "Summer Sale Booster",
"type": "booster",
"channel": "email",
"language": "en_US",
"content": {
"email": {
"subject": "Still on: Summer Sale — Up to 50% Off!"
}
},
"boosterSettings": {
"campaignID": "000000000000000000000001",
"sendTo": "nonOpeners"
},
"sendingSettings": {
"strategy": "scheduled",
"scheduledAt": "2026-06-17T10:00:00Z"
}
}'Only subject is overridden — all other content fields fall back to the parent's snapshot. Call /send when ready.
Example: Create an email booster (draft parent)
curl --request POST \
--url https://api.omnisend.com/api/campaigns \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"name": "Summer Sale Booster",
"type": "booster",
"channel": "email",
"language": "en_US",
"boosterSettings": {
"campaignID": "000000000000000000000001",
"sendTo": "nonOpeners",
"delay": {
"amount": 48,
"unit": "h"
}
}
}'No sendingSettings — the booster is automatically scheduled 48 hours after the parent is sent. Content inherits from the parent.
Example: Create an A/B test campaign
curl --request POST \
--url https://api.omnisend.com/api/campaigns \
--header 'Authorization: Omnisend-API-Key YOUR-API-KEY' \
--header 'Omnisend-Version: 2026-03-15' \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '{
"name": "Subject Line Test",
"type": "abTest",
"channel": "email",
"abTest": {
"settings": {
"testSizePercent": 30,
"winningMetric": "openRate",
"decisionTime": {
"amount": 4,
"unit": "h"
}
},
"variants": {
"a": {
"content": {
"email": {
"subject": "Summer Sale — Up to 50% Off!",
"templateID": "000000000000000000000001"
}
}
},
"b": {
"content": {
"email": {
"subject": "Your exclusive 50% discount is here",
"templateID": "000000000000000000000001"
}
}
}
}
},
"audience": {
"includedSegmentIDs": ["111111111111111111111111"]
},
"sendingSettings": {
"strategy": "scheduled",
"scheduledAt": "2026-12-15T10:00:00Z"
}
}'Creates an A/B test with 30% of the audience receiving variants. After 4 hours, the variant with the higher open rate is sent to the remaining 70%.
UTM Tracking
Each campaign has UTM parameters (source, medium, campaign) appended to links for analytics attribution. Read or update them via the dedicated UTM sub-resource.
| Field | Default | Max length |
|---|---|---|
| source | omnisend | 250 |
| medium | Campaign channel (email, sms, or push) | 250 |
| campaign | campaign: <name> (<id>) | 250 |
| Endpoint | Description |
|---|---|
GET /api/campaigns/{id}/utm | Read current UTM tags (or synthesized defaults) |
PUT /api/campaigns/{id}/utm | Replace UTM tags (campaign must be in draft) |
For A/B test campaigns, UTM tags are set per variant — the response and request body use variants.a / variants.b instead of tags. This allows each variant to be tracked independently in analytics.
Sending an empty string for any field resets it to the default shown above.
For a complete walkthrough, see How to configure UTM tags for campaigns.