Campaigns API
REST endpoints for campaigns in SKUFlow: 21 operations with parameters, request and response fields, permissions and curl examples.
Base URL: https://app.skuflow.ai/api. Every call needs Authorization: Bearer skf_… (Authentication); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id.
| Operation | Endpoint | Risk |
|---|---|---|
| List marketing campaigns | GET /organizations/{organizationId}/marketing/campaigns | read |
| Create a campaign | POST /organizations/{organizationId}/marketing/campaigns | write |
| Get a campaign | GET /organizations/{organizationId}/marketing/campaigns/{campaignId} | read |
| Change a campaign | PATCH /organizations/{organizationId}/marketing/campaigns/{campaignId} | write |
| Delete a campaign | DELETE /organizations/{organizationId}/marketing/campaigns/{campaignId} | sensitive |
| Duplicate a campaign | POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/duplicate | write |
| Preview a campaign | POST /organizations/{organizationId}/marketing/campaigns/preview | write |
| Count an audience | POST /organizations/{organizationId}/marketing/audience/preview | write |
| Draft campaign copy with AI | POST /organizations/{organizationId}/marketing/campaigns/draft | write |
| Send a test to yourself | POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/test | write |
| Send or schedule a campaign | POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/send | sensitive |
| Pause a campaign | POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/pause | write |
| Resume a campaign | POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/resume | sensitive |
| Cancel a campaign | POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/cancel | write |
| A campaign's recipients | GET /organizations/{organizationId}/marketing/campaigns/{campaignId}/recipients | read |
| A campaign's results and revenue | GET /organizations/{organizationId}/marketing/campaigns/{campaignId}/results | read |
| List saved segments | GET /organizations/{organizationId}/marketing/segments | read |
| Save a segment | POST /organizations/{organizationId}/marketing/segments | write |
| Get a segment | GET /organizations/{organizationId}/marketing/segments/{segmentId} | read |
| Change a segment | PATCH /organizations/{organizationId}/marketing/segments/{segmentId} | write |
| Delete a segment | DELETE /organizations/{organizationId}/marketing/segments/{segmentId} | sensitive |
List marketing campaigns
GET /organizations/{organizationId}/marketing/campaigns
Email and text broadcasts, newest first, with status and (once started) results. Read-only.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | campaigns_list (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
status | query | enum | No | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
businessUnitId | query | string | No | Only this business unit (GET /business-units), or "none" for records without one. Up to 100 characters. |
limit | query | integer | No | 1–200. |
offset | query | integer | No |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
total | integer | |
items | array of object | |
items[].id | string | |
items[].name | string | |
items[].status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
items[].channels | array of enum | |
items[].audience | object | |
items[].segment | object or null | |
items[].segment.id | string | |
items[].segment.name | string | |
items[].businessUnitId | string or null | The business unit it is for; null = the whole business. |
items[].emailSubject | string or null | |
items[].emailPreheader | string or null | |
items[].emailBody | string or null | |
items[].smsBody | string or null | |
items[].scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
items[].scheduledAt | string (date-time) or null | |
items[].localDate | string or null | |
items[].localTime | string or null | |
items[].attributionWindowDays | integer | |
items[].utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
items[].trackLinks | boolean | |
items[].audienceCount | integer | Customers in the frozen audience (when started). |
items[].snapshotComplete | boolean | |
items[].startedAt | string (date-time) or null | |
items[].completedAt | string (date-time) or null | |
items[].pausedAt | string (date-time) or null | |
items[].cancelledAt | string (date-time) or null | |
items[].duplicatedFromId | string or null | |
items[].createdAt | string (date-time) | |
items[].updatedAt | string (date-time) | |
items[].problems | array of string | What is missing before it can be sent. |
items[].counts | object or null | Results; null for a campaign never started. |
items[].counts.recipients | integer | Customer × channel rows in the frozen audience. |
items[].counts.pending | integer | Waiting for their send time. |
items[].counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
items[].counts.sent | integer | Handed to the provider (or logged in test mode). |
items[].counts.delivered | integer | |
items[].counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
items[].counts.opened | integer | Where the email provider reports opens. |
items[].counts.clicked | integer | Where the email provider reports clicks. |
items[].counts.bounced | integer | |
items[].counts.failed | integer | |
items[].counts.skipped | integer | Refused by consent, suppression, missing address … |
items[].counts.cancelled | integer | |
items[].counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
items[].counts.byChannel | object | |
items[].counts.skippedReasons | array of object |
Create a campaign
POST /organizations/{organizationId}/marketing/campaigns
Saves a DRAFT campaign (nothing is sent). Preview it with POST /marketing/campaigns/preview, test it with …/test, then send or schedule it with …/send. Always marketing: only customers who agreed to marketing get it.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_create (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Up to 200 characters. |
channels | array of enum | Yes | EMAIL and/or SMS. Each channel reaches the customers whose consent allows it. Up to 2 items. |
audience | object | Yes | { kind: FILTERS, filters } (the audience builder), { kind: SEGMENT, segmentId } or { kind: MANUAL, customerIds }. |
emailSubject | string or null | No | Up to 200 characters. |
emailPreheader | string or null | No | The inbox preview line after the subject. Up to 200 characters. |
emailBody | string or null | No | Plain text or HTML with {{merge.fields}}; goes in the branded email with the unsubscribe footer. |
smsBody | string or null | No | With {{merge.fields}}; "Reply STOP to opt out." is added. Up to 1600 characters. |
scheduleMode | enum | No | NOW when sent; AT scheduledAt; LOCAL_TIME: localDate at localTime in each recipient's timezone (from their state). One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | No | |
localDate | string or null | No | |
localTime | string or null | No | |
attributionWindowDays | integer | No | Days after it reaches someone during which their requests, approved quotes and payments count (default 30). 1–365. |
trackLinks | boolean | No | Add UTM tags to links (default on). |
businessUnitId | string or null | No | The business unit the campaign is for (GET /business-units), for reporting by unit; null = the whole business. Does not narrow the audience. Up to 100 characters. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Dana Whitfield","channels":["EMAIL"],"audience":{"kind":"FILTERS"}}'Response
201: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
Get a campaign
GET /organizations/{organizationId}/marketing/campaigns/{campaignId}
One campaign: content, audience, schedule, status and results (sent, delivered, opened, clicked, bounced, unsubscribed, skipped with reasons). Read-only.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | campaigns_get (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
Change a campaign
PATCH /organizations/{organizationId}/marketing/campaigns/{campaignId}
Changes the fields sent, on a DRAFT or SCHEDULED campaign (a scheduled one goes back to DRAFT and must be sent or scheduled again). 409 once sending: duplicate it instead.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_update (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Up to 200 characters. |
channels | array of enum | No | EMAIL and/or SMS. Each channel reaches the customers whose consent allows it. Up to 2 items. |
audience | object | No | { kind: FILTERS, filters } (the audience builder), { kind: SEGMENT, segmentId } or { kind: MANUAL, customerIds }. |
emailSubject | string or null | No | Up to 200 characters. |
emailPreheader | string or null | No | The inbox preview line after the subject. Up to 200 characters. |
emailBody | string or null | No | Plain text or HTML with {{merge.fields}}; goes in the branded email with the unsubscribe footer. |
smsBody | string or null | No | With {{merge.fields}}; "Reply STOP to opt out." is added. Up to 1600 characters. |
scheduleMode | enum | No | NOW when sent; AT scheduledAt; LOCAL_TIME: localDate at localTime in each recipient's timezone (from their state). One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | No | |
localDate | string or null | No | |
localTime | string or null | No | |
attributionWindowDays | integer | No | Days after it reaches someone during which their requests, approved quotes and payments count (default 30). 1–365. |
trackLinks | boolean | No | Add UTM tags to links (default on). |
businessUnitId | string or null | No | The business unit the campaign is for (GET /business-units), for reporting by unit; null = the whole business. Does not narrow the audience. Up to 100 characters. |
Example
curl -X PATCH "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Dana Whitfield","channels":["EMAIL"],"audience":{"kind":"FILTERS"}}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
Delete a campaign
DELETE /organizations/{organizationId}/marketing/campaigns/{campaignId}
Destructive: deletes a DRAFT or CANCELLED campaign (its messages stay in the message log). A sent campaign keeps its results and cannot be deleted (409).
| Permission | marketing.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | campaigns_delete (toolset marketing) |
| Approval | Over MCP, this tool always waits for your approval in SKUFlow. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Example
curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
ok | true |
Duplicate a campaign
POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/duplicate
A new DRAFT with the same content, audience and settings ("Copy of …"). Nothing is sent.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_duplicate (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/duplicate" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
201: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
Preview a campaign
POST /organizations/{organizationId}/marketing/campaigns/preview
Renders the email (branded, with the unsubscribe footer) and the text (with the opt-out line) for a sample customer of the audience, with the audience's live count and reach by consent, and the text's segments and cost against this month's allowance. Nothing is sent or saved.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_preview (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Up to 200 characters. |
channels | array of enum | Yes | EMAIL and/or SMS. Each channel reaches the customers whose consent allows it. Up to 2 items. |
audience | object | Yes | { kind: FILTERS, filters } (the audience builder), { kind: SEGMENT, segmentId } or { kind: MANUAL, customerIds }. |
emailSubject | string or null | No | Up to 200 characters. |
emailPreheader | string or null | No | The inbox preview line after the subject. Up to 200 characters. |
emailBody | string or null | No | Plain text or HTML with {{merge.fields}}; goes in the branded email with the unsubscribe footer. |
smsBody | string or null | No | With {{merge.fields}}; "Reply STOP to opt out." is added. Up to 1600 characters. |
scheduleMode | enum | No | NOW when sent; AT scheduledAt; LOCAL_TIME: localDate at localTime in each recipient's timezone (from their state). One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | No | |
localDate | string or null | No | |
localTime | string or null | No | |
attributionWindowDays | integer | No | Days after it reaches someone during which their requests, approved quotes and payments count (default 30). 1–365. |
trackLinks | boolean | No | Add UTM tags to links (default on). |
businessUnitId | string or null | No | The business unit the campaign is for (GET /business-units), for reporting by unit; null = the whole business. Does not narrow the audience. Up to 100 characters. |
campaignId | string | No | The campaign being edited (its id goes in utm_content). |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/preview" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"channels":["EMAIL"],"audience":{"kind":"FILTERS"}}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
sampleCustomer | object or null | |
sampleCustomer.id | string | |
sampleCustomer.name | string | |
email | object or null | |
email.subject | string or null | |
email.body | string | |
email.html | string or null | |
email.unresolved | array of string | |
email.blocking | array of string | |
sms | object or null | |
sms.subject | string or null | |
sms.body | string | |
sms.html | string or null | |
sms.unresolved | array of string | |
sms.blocking | array of string | |
audience | object | |
audience.total | integer | Customers in the audience (archived and do-not-service never are). |
audience.checked | integer | Customers whose consent was checked one by one. |
audience.estimated | boolean | Reach scaled from the first customers checked (very large audiences). |
audience.reachable | object | |
audience.reachable.EMAIL | integer | |
audience.reachable.SMS | integer | |
audience.reachable.any | integer | |
audience.unreachable | array of object | |
audience.unreachable[].reason | string | |
audience.unreachable[].text | string | |
audience.unreachable[].count | integer | |
audience.sample | array of object | |
audience.sample[].customerId | string | |
audience.sample[].name | string | |
audience.sample[].email | object | |
audience.sample[].sms | object | |
smsEstimate | object or null | |
smsEstimate.segmentsPerText | integer | |
smsEstimate.encoding | enum | One of GSM-7, UCS-2. |
smsEstimate.characters | integer | |
smsEstimate.recipients | integer | |
smsEstimate.totalSegments | integer | |
smsEstimate.allowanceRemaining | integer or null | |
smsEstimate.overageSegments | integer | |
smsEstimate.overageCents | integer |
Count an audience
POST /organizations/{organizationId}/marketing/audience/preview
The audience builder's live count: how many customers match (archived and do-not-service never do), how many consent lets you email or text for marketing, why the others cannot be reached, and a sample. Nothing is saved.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_audience (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
audience | object | Yes | { kind: FILTERS, filters } (the audience builder), { kind: SEGMENT, segmentId } or { kind: MANUAL, customerIds }. |
channels | array of enum | No | EMAIL and/or SMS. Each channel reaches the customers whose consent allows it. Up to 2 items. Default ["EMAIL"]. |
sampleSize | integer | No | 1–100. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/audience/preview" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"audience":{"kind":"FILTERS"}}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
total | integer | Customers in the audience (archived and do-not-service never are). |
checked | integer | Customers whose consent was checked one by one. |
estimated | boolean | Reach scaled from the first customers checked (very large audiences). |
reachable | object | |
reachable.EMAIL | integer | |
reachable.SMS | integer | |
reachable.any | integer | |
unreachable | array of object | |
unreachable[].reason | string | |
unreachable[].text | string | |
unreachable[].count | integer | |
sample | array of object | |
sample[].customerId | string | |
sample[].name | string | |
sample[].email | object | |
sample[].email.ok | boolean | |
sample[].email.reason | string or null | |
sample[].sms | object | |
sample[].sms.ok | boolean | |
sample[].sms.reason | string or null |
Draft campaign copy with AI
POST /organizations/{organizationId}/marketing/campaigns/draft
Claude writes the email (subject, preheader, body) and the text from your goal, with merge fields, inventing no prices or offers you did not give. Uses AI credits (402 when none are left). source says AI or TEMPLATE (AI off). Nothing is saved: put the answer in the campaign.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_draft (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
goal | string | Yes | What the campaign is for: "Spring team tees, 10% off orders of 48+ until May 31". Up to 1000 characters. |
channels | array of enum | Yes | EMAIL and/or SMS. Each channel reaches the customers whose consent allows it. Up to 2 items. |
tone | enum | No | One of friendly, professional, urgent. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/draft" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"goal":"string","channels":["EMAIL"]}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
source | enum | One of AI, FAKE, TEMPLATE. |
Send a test to yourself
POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/test
Sends the campaign marked "[Test]" to your own email (default: your account's) and/or phone, rendered for a sample customer of the audience. Logged as TEST; never counted in results; no customer gets it.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_test (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
email | empty string or string (email) or null | No | Where to send the test email; default your account's email. |
phone | string or null | No | Where to send the test text (the campaign must have one). Up to 40 characters. |
now | string (date-time) | No | Tests only: act as of this moment (ISO 8601). Refused when NODE_ENV=production. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/test" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"dana@example.com","phone":"+15555550123","now":"2026-11-03T15:00:00Z"}'Response
200: the answer's fields
An array of objects:
| Field | Type | Description |
|---|---|---|
id | string | |
channel | enum | One of EMAIL, SMS. |
status | string | |
statusReason | string or null | |
toAddress | string or null | |
subject | string or null |
Send or schedule a campaign
POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/send
Customer-visible: sends the DRAFT now, or schedules it (its scheduleMode). The audience is frozen; each customer gets it once per channel, only when marketing consent allows (opted in, not unsubscribed, not suppressed, OK to text for texts), with the unsubscribe footer or STOP line, held by quiet hours. Large audiences go out in pages. Preview and test it first.
| Permission | marketing.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | campaigns_send (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
| Approval | Over MCP, this tool always waits for your approval in SKUFlow. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
now | string (date-time) | No | Tests only: act as of this moment (ISO 8601). Refused when NODE_ENV=production. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/send" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"now":"2026-11-03T15:00:00Z"}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
Pause a campaign
POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/pause
Stops a scheduled or sending campaign: nothing new is queued and messages held (quiet hours) are withdrawn. Messages already handed to the provider are not recalled. Resume with …/resume.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_pause (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
now | string (date-time) | No | Tests only: act as of this moment (ISO 8601). Refused when NODE_ENV=production. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/pause" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"now":"2026-11-03T15:00:00Z"}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
Resume a campaign
POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/resume
Customer-visible: a paused campaign continues where it stopped; nobody gets it twice.
| Permission | marketing.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | campaigns_resume (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
| Approval | Over MCP, this tool always waits for your approval in SKUFlow. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
now | string (date-time) | No | Tests only: act as of this moment (ISO 8601). Refused when NODE_ENV=production. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/resume" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"now":"2026-11-03T15:00:00Z"}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
Cancel a campaign
POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/cancel
Ends a scheduled, sending or paused campaign for good: the rest of the audience never gets it. Results so far are kept.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | campaigns_cancel (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
now | string (date-time) | No | Tests only: act as of this moment (ISO 8601). Refused when NODE_ENV=production. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/cancel" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"now":"2026-11-03T15:00:00Z"}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
status | enum | One of DRAFT, SCHEDULED, SENDING, PAUSED, SENT, CANCELLED. |
channels | array of enum | |
audience | object | |
segment | object or null | |
segment.id | string | |
segment.name | string | |
businessUnitId | string or null | The business unit it is for; null = the whole business. |
emailSubject | string or null | |
emailPreheader | string or null | |
emailBody | string or null | |
smsBody | string or null | |
scheduleMode | enum | One of NOW, AT, LOCAL_TIME. |
scheduledAt | string (date-time) or null | |
localDate | string or null | |
localTime | string or null | |
attributionWindowDays | integer | |
utmCampaign | string or null | utm_campaign on its links (fixed when it starts). |
trackLinks | boolean | |
audienceCount | integer | Customers in the frozen audience (when started). |
snapshotComplete | boolean | |
startedAt | string (date-time) or null | |
completedAt | string (date-time) or null | |
pausedAt | string (date-time) or null | |
cancelledAt | string (date-time) or null | |
duplicatedFromId | string or null | |
createdAt | string (date-time) | |
updatedAt | string (date-time) | |
problems | array of string | What is missing before it can be sent. |
counts | object or null | Results; null for a campaign never started. |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer |
A campaign's recipients
GET /organizations/{organizationId}/marketing/campaigns/{campaignId}/recipients
Who is in the frozen audience, per channel: when it goes, what became of it (queued, skipped with the reason, sent, opened, clicked). Read-only.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | campaigns_recipients (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
status | query | enum | No | One of PENDING, QUEUED, SKIPPED, FAILED, CANCELLED. |
channel | query | enum | No | One of EMAIL, SMS. |
limit | query | integer | No | 1–200. |
offset | query | integer | No |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/recipients" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
total | integer | |
items | array of object | |
items[].id | string | |
items[].customerId | string | |
items[].customerName | string | |
items[].channel | enum | One of EMAIL, SMS. |
items[].status | string | |
items[].reason | string or null | |
items[].sendAt | string (date-time) | |
items[].timeZone | string or null | |
items[].messageId | string or null | |
items[].messageStatus | string or null | |
items[].sentAt | string (date-time) or null | |
items[].openedAt | string (date-time) or null | |
items[].clickedAt | string (date-time) or null |
A campaign's results and revenue
GET /organizations/{organizationId}/marketing/campaigns/{campaignId}/results
Delivery and engagement counts, plus attribution: requests, approved quotes and paid invoices (with revenue) by recipients within the attribution window after it reached them, and requests carrying its UTM tags. Read-only.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | campaigns_results (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A campaign id, from GET /marketing/campaigns. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/results" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
counts | object | |
counts.recipients | integer | Customer × channel rows in the frozen audience. |
counts.pending | integer | Waiting for their send time. |
counts.queued | integer | Queued or held by quiet hours, not handed to the provider yet. |
counts.sent | integer | Handed to the provider (or logged in test mode). |
counts.delivered | integer | |
counts.testMode | integer | Logged in test mode (no provider): counted in sent. |
counts.opened | integer | Where the email provider reports opens. |
counts.clicked | integer | Where the email provider reports clicks. |
counts.bounced | integer | |
counts.failed | integer | |
counts.skipped | integer | Refused by consent, suppression, missing address … |
counts.cancelled | integer | |
counts.unsubscribed | integer | Opted out of marketing (link, STOP, complaint) after it reached them. |
counts.byChannel | object | |
counts.byChannel.EMAIL | object | |
counts.byChannel.SMS | object | |
counts.skippedReasons | array of object | |
counts.skippedReasons[].reason | string | |
counts.skippedReasons[].count | integer | |
attribution | object | |
attribution.windowDays | integer | |
attribution.utmCampaign | string or null | |
attribution.reached | integer | Customers it reached (sent, delivered or logged in test mode). |
attribution.requests | integer | |
attribution.quotesApproved | integer | |
attribution.invoicesPaid | integer | |
attribution.revenueCents | integer | Total of the invoices recipients paid in the window. |
List saved segments
GET /organizations/{organizationId}/marketing/segments
Saved audiences (named sets of audience-builder filters) for campaigns, by name. Read-only.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | segments_list (toolset marketing) |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/segments" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
An array of objects:
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
description | string or null | |
filters | object | |
filters.tagsAny | array of string | Customers with at least one of these tags. Up to 50 items. |
filters.tagsNone | array of string | Leave out customers with any of these tags. Up to 50 items. |
filters.customerTypes | array of enum | Up to 2 items. |
filters.zips | array of string | An address (or the billing address) in one of these ZIP codes. Up to 500 items. |
filters.cities | array of string | Up to 100 items. |
filters.lifetimeValueMinCents | integer | 0–100000000. |
filters.lifetimeValueMaxCents | integer | 0–100000000. |
filters.behaviours | array of string | Customer 360 behaviours, all of them (BOOKS_ONLINE, PAYS_ON_TIME …). Up to 20 items. |
filters.atRisk | boolean | Customer 360: health AT_RISK or a HIGH lapse risk. |
filters.leadSourceIds | array of string | Up to 50 items. |
createdAt | string (date-time) | |
updatedAt | string (date-time) |
Save a segment
POST /organizations/{organizationId}/marketing/segments
Saves audience filters under a name, for campaigns (the filters are applied when a campaign starts, so the segment stays current).
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | segments_create (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Up to 120 characters. |
description | string or null | No | Up to 500 characters. |
filters | object | Yes | The audience builder's filters: tags, customer type, ZIPs and cities, lifetime value, Customer 360 behaviours and at risk, lead sources. |
filters.tagsAny | array of string | No | Customers with at least one of these tags. Up to 50 items. |
filters.tagsNone | array of string | No | Leave out customers with any of these tags. Up to 50 items. |
filters.customerTypes | array of enum | No | Up to 2 items. |
filters.zips | array of string | No | An address (or the billing address) in one of these ZIP codes. Up to 500 items. |
filters.cities | array of string | No | Up to 100 items. |
filters.lifetimeValueMinCents | integer | No | 0–100000000. |
filters.lifetimeValueMaxCents | integer | No | 0–100000000. |
filters.behaviours | array of string | No | Customer 360 behaviours, all of them (BOOKS_ONLINE, PAYS_ON_TIME …). Up to 20 items. |
filters.atRisk | boolean | No | Customer 360: health AT_RISK or a HIGH lapse risk. |
filters.leadSourceIds | array of string | No | Up to 50 items. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/segments" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Dana Whitfield","filters":{"tagsAny":["string"],"tagsNone":["string"],"customerTypes":["RESIDENTIAL"]}}'Response
201: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
description | string or null | |
filters | object | |
filters.tagsAny | array of string | Customers with at least one of these tags. Up to 50 items. |
filters.tagsNone | array of string | Leave out customers with any of these tags. Up to 50 items. |
filters.customerTypes | array of enum | Up to 2 items. |
filters.zips | array of string | An address (or the billing address) in one of these ZIP codes. Up to 500 items. |
filters.cities | array of string | Up to 100 items. |
filters.lifetimeValueMinCents | integer | 0–100000000. |
filters.lifetimeValueMaxCents | integer | 0–100000000. |
filters.behaviours | array of string | Customer 360 behaviours, all of them (BOOKS_ONLINE, PAYS_ON_TIME …). Up to 20 items. |
filters.atRisk | boolean | Customer 360: health AT_RISK or a HIGH lapse risk. |
filters.leadSourceIds | array of string | Up to 50 items. |
createdAt | string (date-time) | |
updatedAt | string (date-time) |
Get a segment
GET /organizations/{organizationId}/marketing/segments/{segmentId}
One saved audience: its name, description and audience-builder filters. Read-only.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | segments_get (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
segmentId | path | string | Yes | A saved segment id, from GET /marketing/segments. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/segments/{segmentId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
description | string or null | |
filters | object | |
filters.tagsAny | array of string | Customers with at least one of these tags. Up to 50 items. |
filters.tagsNone | array of string | Leave out customers with any of these tags. Up to 50 items. |
filters.customerTypes | array of enum | Up to 2 items. |
filters.zips | array of string | An address (or the billing address) in one of these ZIP codes. Up to 500 items. |
filters.cities | array of string | Up to 100 items. |
filters.lifetimeValueMinCents | integer | 0–100000000. |
filters.lifetimeValueMaxCents | integer | 0–100000000. |
filters.behaviours | array of string | Customer 360 behaviours, all of them (BOOKS_ONLINE, PAYS_ON_TIME …). Up to 20 items. |
filters.atRisk | boolean | Customer 360: health AT_RISK or a HIGH lapse risk. |
filters.leadSourceIds | array of string | Up to 50 items. |
createdAt | string (date-time) | |
updatedAt | string (date-time) |
Change a segment
PATCH /organizations/{organizationId}/marketing/segments/{segmentId}
Replaces its name, description and filters.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | segments_update (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
segmentId | path | string | Yes | A saved segment id, from GET /marketing/segments. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Up to 120 characters. |
description | string or null | No | Up to 500 characters. |
filters | object | Yes | The audience builder's filters: tags, customer type, ZIPs and cities, lifetime value, Customer 360 behaviours and at risk, lead sources. |
filters.tagsAny | array of string | No | Customers with at least one of these tags. Up to 50 items. |
filters.tagsNone | array of string | No | Leave out customers with any of these tags. Up to 50 items. |
filters.customerTypes | array of enum | No | Up to 2 items. |
filters.zips | array of string | No | An address (or the billing address) in one of these ZIP codes. Up to 500 items. |
filters.cities | array of string | No | Up to 100 items. |
filters.lifetimeValueMinCents | integer | No | 0–100000000. |
filters.lifetimeValueMaxCents | integer | No | 0–100000000. |
filters.behaviours | array of string | No | Customer 360 behaviours, all of them (BOOKS_ONLINE, PAYS_ON_TIME …). Up to 20 items. |
filters.atRisk | boolean | No | Customer 360: health AT_RISK or a HIGH lapse risk. |
filters.leadSourceIds | array of string | No | Up to 50 items. |
Example
curl -X PATCH "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/segments/{segmentId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Dana Whitfield","filters":{"tagsAny":["string"],"tagsNone":["string"],"customerTypes":["RESIDENTIAL"]}}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
id | string | |
name | string | |
description | string or null | |
filters | object | |
filters.tagsAny | array of string | Customers with at least one of these tags. Up to 50 items. |
filters.tagsNone | array of string | Leave out customers with any of these tags. Up to 50 items. |
filters.customerTypes | array of enum | Up to 2 items. |
filters.zips | array of string | An address (or the billing address) in one of these ZIP codes. Up to 500 items. |
filters.cities | array of string | Up to 100 items. |
filters.lifetimeValueMinCents | integer | 0–100000000. |
filters.lifetimeValueMaxCents | integer | 0–100000000. |
filters.behaviours | array of string | Customer 360 behaviours, all of them (BOOKS_ONLINE, PAYS_ON_TIME …). Up to 20 items. |
filters.atRisk | boolean | Customer 360: health AT_RISK or a HIGH lapse risk. |
filters.leadSourceIds | array of string | Up to 50 items. |
createdAt | string (date-time) | |
updatedAt | string (date-time) |
Delete a segment
DELETE /organizations/{organizationId}/marketing/segments/{segmentId}
Destructive: deletes a saved audience. 409 while a running campaign uses it.
| Permission | marketing.manage (Owner, Admin) |
| Risk | sensitive, OAuth scope skuflow.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access. |
| MCP tool | segments_delete (toolset marketing) |
| Approval | Over MCP, this tool always waits for your approval in SKUFlow. See Approvals. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
segmentId | path | string | Yes | A saved segment id, from GET /marketing/segments. |
Example
curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/segments/{segmentId}" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
ok | true |