Marketing API
REST endpoints for marketing in SKUFlow: 4 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 |
|---|---|---|
| Get a campaign email's design | GET /organizations/{organizationId}/marketing/campaigns/{campaignId}/design | read |
| Save a campaign email's design | PUT /organizations/{organizationId}/marketing/campaigns/{campaignId}/design | write |
| Reset a campaign email's design | DELETE /organizations/{organizationId}/marketing/campaigns/{campaignId}/design | sensitive |
| Draft a campaign email's design with AI | POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/design/draft | write |
Get a campaign email's design
GET /organizations/{organizationId}/marketing/campaigns/{campaignId}/design
The campaign email's block design (custom: true) or the starter (custom: false). A campaign's own blocks may replace its message; the footer (address and unsubscribe) stays. Read-only.
| Permission | marketing.read (Owner, Admin, Staff) |
| Risk | read, OAuth scope skuflow.read. Read: reads only. |
| MCP tool | emailDesigns_getCampaign (toolset marketing) |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A marketing campaign id, from GET /marketing/campaigns. |
Example
curl "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/design" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
target | object | |
target.kind | enum | One of template, campaign. |
target.id | string | |
target.name | string | |
target.subject | string or null | |
target.body | string | The message block's text (edit it on the template or campaign). |
target.preheader | string or null | |
target.purpose | enum | One of TRANSACTIONAL, MARKETING. |
target.systemKey | string or null | |
target.editable | boolean | False for a campaign that started (only drafts and scheduled ones change). |
custom | boolean | True: the email uses this design. False: the default design; document is the starter. |
document | object | |
document.version | integer | |
document.blocks | array of object | |
document.blocks[].id | string | |
document.blocks[].type | enum | One of header, heading, text, image, button, divider, spacer, columns, social, message, record, footer. |
required | array of object | Blocks this email must keep (they can move and change style, not be deleted). |
required[].type | enum | One of message, footer, record. |
required[].kind | enum | One of invoice, quote, payment. |
recordKind | enum or null | One of invoice, quote, payment. |
updatedAt | string (date-time) or null |
Save a campaign email's design
PUT /organizations/{organizationId}/marketing/campaigns/{campaignId}/design
Replaces the campaign email's design (a draft or scheduled campaign only; 400 otherwise). Customers get it when the campaign sends. Sends nothing.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | emailDesigns_updateCampaign (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A marketing campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
document | object | Yes | The design: { version: 1, blocks: [...] }. Blocks (each { id, type, style: { background, paddingTop, paddingBottom, paddingX } }): header { showHeaderText, showBanner }, heading { text, level 1-3, align }, text { text with **bold**, *italic*, label and {{merge.fields}} }, image { url (an uploaded image's url or https://), alt, href, width % , align }, button { label, url (https://… or a merge link such as {{links.invoice}}), align, fullWidth }, divider { color, thickness }, spacer { height }, columns { columns: 2-3 × { blocks: heading/text/image/button }, stackOnMobile }, social { align }, message (the template's or campaign's text), record { kind invoice|quote|visit|payment|membership, showButton, buttonLabel }, footer (your address and the unsubscribe link). GET the design first and send it back changed. |
document.version | 1 | No | Default 1. |
document.blocks | array of object | Yes | Up to 60 items. |
Example
curl -X PUT "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/design" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"document":{"blocks":[{"id":"id_id","type":"header"}]}}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
target | object | |
target.kind | enum | One of template, campaign. |
target.id | string | |
target.name | string | |
target.subject | string or null | |
target.body | string | The message block's text (edit it on the template or campaign). |
target.preheader | string or null | |
target.purpose | enum | One of TRANSACTIONAL, MARKETING. |
target.systemKey | string or null | |
target.editable | boolean | False for a campaign that started (only drafts and scheduled ones change). |
custom | boolean | True: the email uses this design. False: the default design; document is the starter. |
document | object | |
document.version | integer | |
document.blocks | array of object | |
document.blocks[].id | string | |
document.blocks[].type | enum | One of header, heading, text, image, button, divider, spacer, columns, social, message, record, footer. |
required | array of object | Blocks this email must keep (they can move and change style, not be deleted). |
required[].type | enum | One of message, footer, record. |
required[].kind | enum | One of invoice, quote, payment. |
recordKind | enum or null | One of invoice, quote, payment. |
updatedAt | string (date-time) or null |
Reset a campaign email's design
DELETE /organizations/{organizationId}/marketing/campaigns/{campaignId}/design
Destructive: deletes the campaign email's own design (a draft or scheduled campaign only); it goes back to the default design with the campaign's text.
| 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 | emailDesigns_resetCampaign (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 marketing campaign id, from GET /marketing/campaigns. |
Example
curl -X DELETE "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/design" \
-H "Authorization: Bearer $SKUFLOW_API_KEY"Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
target | object | |
target.kind | enum | One of template, campaign. |
target.id | string | |
target.name | string | |
target.subject | string or null | |
target.body | string | The message block's text (edit it on the template or campaign). |
target.preheader | string or null | |
target.purpose | enum | One of TRANSACTIONAL, MARKETING. |
target.systemKey | string or null | |
target.editable | boolean | False for a campaign that started (only drafts and scheduled ones change). |
custom | boolean | True: the email uses this design. False: the default design; document is the starter. |
document | object | |
document.version | integer | |
document.blocks | array of object | |
document.blocks[].id | string | |
document.blocks[].type | enum | One of header, heading, text, image, button, divider, spacer, columns, social, message, record, footer. |
required | array of object | Blocks this email must keep (they can move and change style, not be deleted). |
required[].type | enum | One of message, footer, record. |
required[].kind | enum | One of invoice, quote, payment. |
recordKind | enum or null | One of invoice, quote, payment. |
updatedAt | string (date-time) or null |
Draft a campaign email's design with AI
POST /organizations/{organizationId}/marketing/campaigns/{campaignId}/design/draft
Claude lays out the campaign email as blocks from a short request ("summer promo, bold, with a coupon button"): a heading and short text around the campaign's message, buttons to the business's own links, images from its library; no prices, discounts or coupon codes that the request or the campaign text does not state. The footer (address and unsubscribe) is kept. Needs the campaigns feature. Uses AI credits (402 when none are left); source TEMPLATE when AI is off. Nothing is saved: preview with POST /email-designs/preview document and campaignId, save with PUT …/marketing/campaigns/{campaignId}/design.
| Permission | marketing.manage (Owner, Admin) |
| Risk | write, OAuth scope skuflow.write. Write: creates or changes records inside the business; nothing leaves it. |
| MCP tool | emailDesigns_draftCampaignDesign (toolset marketing) |
| Plan | Marketing campaigns: the Grow plan and up. |
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaignId | path | string | Yes | A marketing campaign id, from GET /marketing/campaigns. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | What the email should look like: "summer promo, bold, with a coupon button". Up to 600 characters. |
document | object | No | The design being edited with unsaved changes (the draft builds on it); omit for the saved one. |
document.version | 1 | No | Default 1. |
document.blocks | array of object | Yes | Up to 60 items. |
Example
curl -X POST "https://app.skuflow.ai/api/organizations/$ORGANIZATION_ID/marketing/campaigns/{campaignId}/design/draft" \
-H "Authorization: Bearer $SKUFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"string"}'Response
200: the answer's fields
| Field | Type | Description |
|---|---|---|
document | object | The drafted design ({ version: 1, blocks }), valid for this email and keeping its locked blocks and footer. Not saved: preview it with POST /email-designs/preview document, save it with PUT …/design. |
document.version | integer | |
document.blocks | array of object | |
document.blocks[].id | string | |
document.blocks[].type | enum | One of header, heading, text, image, button, divider, spacer, columns, social, message, record, footer. |
source | enum | Ai: Claude drafted it. TEMPLATE: AI is off or unavailable (a starter from your brand). One of AI, FAKE, TEMPLATE. |
notes | array of string | The AI's note on the design. |
warnings | array of string | What was left out of the AI's draft and why: an image not in the library, a link or price you didn't give, a merge field that doesn't exist. |