Organization API: Org Staff Marketing: Staff
The 45 Organization API operations for staff.
Part of Org Staff Marketing.
Operations
Section titled OperationsGet ads
Section titled Get adsGET /api/v1/orgs/{org_slug}/staff/marketing/ads
Every ad platform with its status, every connected ad account, and the last 30 days of spend.
Needs the Admin or Owner role. platforms lists Google Ads, Meta Ads, TikTok Ads, Microsoft Ads and Reddit
Ads. A platform's status is not_configured (Coritan has not added its app credentials, so it cannot be
connected), not_connected, pending (signed in, no account picked yet), connected, failing (an
account has had errors and no successful read for an hour) or reauth (the sign-in ended, so connect
again). connections has one entry for each ad account the sign-in found, with the same status words
(an account that is found but not picked reads pending), when it was last read, the last error, how far
its 13 month history has been read and its spend per currency. summary is the last 30 days of spend per
currency, with entered spend included. warning is set when a sign-in ends within 14 days. Nothing here
carries a token.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Disconnect one ad account
Section titled Disconnect one ad accountDELETE /api/v1/orgs/{org_slug}/staff/marketing/ads/connections/{connection_id}
Disconnect one ad account.
Needs the Admin or Owner role. The account's saved sign-in is deleted and nothing is read from it again. The spend already imported stays in your reports. Connect the platform again to read the account again.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
connection_id |
path | integer | yes |
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read one ad account now
Section titled Read one ad account nowPOST /api/v1/orgs/{org_slug}/staff/marketing/ads/connections/{connection_id}/sync
Read one ad account now.
Needs the Admin or Owner role. With no body it reads today and the two days before. With from and to
it reads those days again (at most 400, none before 13 months ago), which is how to refresh a month after the
platform adjusts its numbers. The read runs in the background: check last_sync_at on the account.
Answers 409 when the account's sign-in has ended or the account is not picked, and 429 after 4 requests an
hour for one account.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
connection_id |
path | integer | yes |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date) or null | no | The first day to read again. Send it with to, or send neither. |
to |
string (date) or null | no | The last day to read again. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
202 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Get ad return
Section titled Get ad returnGET /api/v1/orgs/{org_slug}/staff/marketing/ads/return
What the ad spend returned: orders, new customers, revenue, CAC and ROAS per platform, and per campaign.
Needs the Admin or Owner role. An order counts for the platform its last touch came from, when its invoice is
paid and it is not free: the touch's source and medium name the platform, and when they do not, its click ids
do. Within a platform an order counts for the campaign whose name (or id) equals its utm_campaign, ignoring
case. new_customers counts customers whose first paid order it was. roas is revenue without tax over
spend, cac_minor is spend over new customers, and platform_roas is the value the platform reports over
spend. Each is empty when its divisor is zero. Rows are per currency: spend and revenue meet only when they
are in the same currency, so an ad account billed in one currency and customers paying in another show as
separate rows with no CAC or ROAS. Payback is not computed, because it needs a gross margin that is not kept.
truncated is true when more than 50,000 orders were in the range.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
from |
query | string (date) or null | no | The first day, as YYYY-MM-DD. The default is 30 days before to. |
to |
query | string (date) or null | no | The last day, as YYYY-MM-DD, included. The default is today in the organization's time zone. |
group |
query | string | no | platform or campaign. Default: platform. |
currency |
query | string or null | no | Only this currency. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
What was spent, grouped by platform, campaign or day
Section titled What was spent, grouped by platform, campaign or dayGET /api/v1/orgs/{org_slug}/staff/marketing/ads/spend
What was spent, grouped by platform, campaign or day.
Needs the Admin or Owner role. Every row is in one currency, and a platform that spent in two currencies has
two rows: amounts in different currencies are never added. totals is the whole range per currency, even
when limit (rows for each currency, by campaign) cuts the rows. Spend entered by hand is included, spread evenly over its days. The range is at
most 400 days. Days follow each ad account's own time zone (Microsoft Ads and Reddit Ads follow the
organization's), so a day's spend can differ a little from the platform's own report in another zone.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
from |
query | string (date) or null | no | The first day, as YYYY-MM-DD. The default is 30 days before to. |
to |
query | string (date) or null | no | The last day, as YYYY-MM-DD, included. The default is today in the organization's time zone. |
group |
query | string | no | platform, campaign or day. Default: platform. |
currency |
query | string or null | no | Only this currency. |
limit |
query | integer | no | Rows to return for each currency when grouping by campaign. Default: 100. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Spend entered by hand, newest first
Section titled Spend entered by hand, newest firstGET /api/v1/orgs/{org_slug}/staff/marketing/ads/spend/manual
Spend entered by hand, newest first.
Needs the Admin or Owner role. ignored is true for an entry whose channel has since been connected, which
reports leave out because the platform's own numbers cover it.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
limit |
query | integer | no | Entries to return, newest first. Default: 100. |
offset |
query | integer | no | Entries to skip. Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Enter spend for a channel that has no connection
Section titled Enter spend for a channel that has no connectionPOST /api/v1/orgs/{org_slug}/staff/marketing/ads/spend/manual
Enter spend for a channel that has no connection.
Needs the Admin or Owner role. amount_minor is the whole amount over starts_on to ends_on (at most
400 days), and reports spread it evenly over those days. A platform with a picked account, or one that was already
read for some of these days, is refused with 409 because its own numbers cover it. Answers 422 for a
channel, currency, amount or dates that do not fit.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
channel |
string | yes | Where the money was spent: a platform key or another network such as x, linkedin, snapchat, pinterest or other. |
label |
string | yes | What the spend was for, in your words. |
currency |
string | yes | The three letter code of the currency it was paid in. |
amount_minor |
integer | yes | The whole amount over the days, in the currency's smallest unit (cents for USD). |
starts_on |
string (date) | yes | The first day the spend covers. |
ends_on |
string (date) | yes | The last day the spend covers. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
201 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Remove an entry of spend entered by hand
Section titled Remove an entry of spend entered by handDELETE /api/v1/orgs/{org_slug}/staff/marketing/ads/spend/manual/{entry_id}
Remove an entry of spend entered by hand. Needs the Admin or Owner role.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
entry_id |
path | integer | yes |
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Pick which of the platform's accounts to read
Section titled Pick which of the platform's accounts to readPOST /api/v1/orgs/{org_slug}/staff/marketing/ads/{platform}/accounts
Pick which of the platform's accounts to read.
Needs the Admin or Owner role. account_ids is the whole list: accounts you name start being read (their
13 month history first), and accounts of this platform you leave out stop being read but keep the spend
already imported. At most 50 accounts for one platform. Answers 422 for an account that is not on the
sign-in. Pick only the accounts that belong to this organization: a sign-in to a manager account can list
accounts that are not yours.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
platform |
path | string | yes | One of google, meta, tiktok, microsoft, reddit. |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
account_ids |
array of string | yes | The accounts to read, by the platform's own ids. Accounts of the platform that are not listed stop being read. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Start signing in to an ad platform
Section titled Start signing in to an ad platformPOST /api/v1/orgs/{org_slug}/staff/marketing/ads/{platform}/connect
Start signing in to an ad platform. Answers authorization_url, the platform's own page.
Needs the Admin or Owner role. Send the person to authorization_url. The platform sends the browser back
to Coritan, which finds the accounts the sign-in can read and returns the person to return_path (a page of
the console on the host of this request) with ads=connected or ads=error in the address. The link is good
for 15 minutes. Answers 409 not_configured when the platform's app credentials have not been added to
Coritan, and 422 when the request does not come from one of your console's hosts.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
platform |
path | string | yes | One of google, meta, tiktok, microsoft, reddit. |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json
| Field | Type | Required | Description |
|---|---|---|---|
return_path |
string or null | no | The page of the console to come back to when the sign-in is done, such as /staff/marketing/ads. It is a path on the host the request came from. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read the Discord webhook settings for announcements
Section titled Read the Discord webhook settings for announcementsGET /api/v1/orgs/{org_slug}/staff/marketing/announcements
Whether a Discord webhook is saved for announcements, and its channel label.
Needs the Admin or Owner role. configured says whether a webhook address is saved, channel_label is the
name your team gave the channel (null for none) and webhook_hint is the last four characters of the
webhook's ID, so you can tell which webhook is saved. The address is a secret and is never answered.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Save or remove the Discord webhook for announcements
Section titled Save or remove the Discord webhook for announcementsPUT /api/v1/orgs/{org_slug}/staff/marketing/announcements
Save the Discord webhook address and the channel label. Send only what changes.
Needs the Admin or Owner role. webhook_url must be an https address on Discord's own hosts that starts
with https://discord.com/api/webhooks/, or 422 answers with detail and field. It is sealed and never
shown again, and null or an empty string removes it. channel_label is at most 80 characters. The answer
is the one GET gives. Saving what is already saved changes nothing and writes no audit entry. A change is
recorded as announcements.updated with the settings that changed and never the address.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
webhook_url |
string or null | no | The Discord webhook address, which starts with https://discord.com/api/webhooks/. It is sealed and never shown again. Null or empty removes the saved one. Left out, the saved one stays. |
channel_label |
string or null | no | A name for the channel, such as #announcements, shown to your team. At most 80 characters. Null or empty removes it. Left out, the saved one stays. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read the announcements that were posted
Section titled Read the announcements that were postedGET /api/v1/orgs/{org_slug}/staff/marketing/announcements/history
The announcements posted or refused, newest first.
Needs the Admin or Owner role. Each entry has status (posted or failed), the title, content and
link that were sent, the channel_label then saved, error (why a failed post failed, never what
Discord said), actor_type (staff, user or admin for platform staff), actor ({id, name}, null
when it is unknown) and created_at. The webhook address is never in an entry.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
limit |
query | integer | no | Announcements to return, newest first, 1 to 100. Left out, 20. Default: 20. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Post an announcement to Discord
Section titled Post an announcement to DiscordPOST /api/v1/orgs/{org_slug}/staff/marketing/announcements/post
Post one message to the saved Discord webhook.
Needs the Admin or Owner role. content is the message, 1 to 1,800 characters. title (at most 120
characters) becomes a bold first line, and link (an https address) goes after the message. The title,
text and link together fit Discord's 2,000 characters, or 422 answers. Nothing in the message can mention
a role or a person. The answer is {posted: true}. 409 means no webhook is saved. 502 means Discord did
not take the message, with detail saying so in a sentence, and nothing was posted. At most 10 messages
an hour for the organization, and the 11th answers 429. Every attempt is recorded in the audit log as
announcement.posted or announcement.failed with the words and the channel label, never the address.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
content |
string or null | no | The message, 1 to 1,800 characters. Discord's own formatting works in it. Nothing in it can mention a role or a person. |
title |
string or null | no | A bold first line, at most 120 characters. |
link |
string or null | no | A link added after the message. It starts with https://, at most 500 characters. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
List the campaign links
Section titled List the campaign linksGET /api/v1/orgs/{org_slug}/staff/marketing/campaigns
The organization's saved campaign links, newest first.
Needs the Billing, Admin or Owner role. A campaign is a landing page with the UTM words that tag it and an
optional coupon. Every campaign has all its fields, archived (true once it was archived) and url, the
full link to copy: the storefront address, base_path, the UTM words in the order utm_source,
utm_medium, utm_campaign, utm_term, utm_content, then coupon. The words are percent encoded. An
organization with no storefront address gets the path and query alone. count is how many campaigns
match before limit and offset apply, and max_campaigns is the most an organization keeps.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
status |
query | string | no | all (the default), active or archived. Default: all. |
q |
query | string or null | no | Only campaigns whose name or campaign word holds this text, ignoring capitals. |
limit |
query | integer | no | Campaigns to return, 1 to 200. Left out, 100. Default: 100. |
offset |
query | integer | no | Campaigns to skip, for the next page. Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Save a campaign link
Section titled Save a campaign linkPOST /api/v1/orgs/{org_slug}/staff/marketing/campaigns
Save a campaign link and answer it, with its url.
Needs the Billing, Admin or Owner role. name, utm_source, utm_medium and utm_campaign are
required. A bad value answers 422 with detail, the sentence to show, and field, the input it belongs
to. A name another campaign already has, in any capitals, answers 409 with field name. An
organization keeps at most 500 campaigns, and the 501st answers 409. A coupon_code must be a coupon of
this organization. The change is recorded in the audit log as campaign.created.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name |
string or null | no | What you call the campaign, at most 120 characters. Each campaign in an organization has its own name, and two names that differ only in capitals count as one. |
base_path |
string or null | no | The page the link opens: a path on your storefront that starts with /, at most 400 characters, such as /pricing. It holds no host, scheme, fragment, backslash, space or control character, and at most one ?. A query in it is kept and the UTM words go after it. Left out when you create a campaign, it is /. |
utm_source |
string or null | no | Where the visit comes from, such as newsletter. At most 80 characters, with no &, =, #, ? or control character. |
utm_medium |
string or null | no | How the link is delivered, such as email. At most 80 characters, with the same limits as the source. |
utm_campaign |
string or null | no | The word the reports group by, at most 120 characters, with the same limits as the source. A visit or order whose campaign is this word belongs to the campaign, whatever its capitals. |
utm_term |
string or null | no | The keyword or audience, at most 120 characters. Empty or null for none. |
utm_content |
string or null | no | Tells two links of one campaign apart, at most 120 characters. Empty or null for none. |
coupon_code |
string or null | no | A coupon of this organization that the link applies, as ?coupon=. It must exist. Empty or null for none. |
notes |
string or null | no | A note for your team, at most 500 characters. Empty or null for none. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
201 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Check a campaign link and build its address without saving it
Section titled Check a campaign link and build its address without saving itPOST /api/v1/orgs/{org_slug}/staff/marketing/campaigns/preview
Build the link for the fields sent, and list what is wrong with them. Saves nothing.
Needs the Billing, Admin or Owner role. Send the same body as a save; name may be left out. The answer
is {url, problems}. problems is a list of {field, detail} with every problem found, and url is null
while there is one. The check is the one a save makes, a repeated name and an unknown coupon included.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name |
string or null | no | What you call the campaign, at most 120 characters. Each campaign in an organization has its own name, and two names that differ only in capitals count as one. |
base_path |
string or null | no | The page the link opens: a path on your storefront that starts with /, at most 400 characters, such as /pricing. It holds no host, scheme, fragment, backslash, space or control character, and at most one ?. A query in it is kept and the UTM words go after it. Left out when you create a campaign, it is /. |
utm_source |
string or null | no | Where the visit comes from, such as newsletter. At most 80 characters, with no &, =, #, ? or control character. |
utm_medium |
string or null | no | How the link is delivered, such as email. At most 80 characters, with the same limits as the source. |
utm_campaign |
string or null | no | The word the reports group by, at most 120 characters, with the same limits as the source. A visit or order whose campaign is this word belongs to the campaign, whatever its capitals. |
utm_term |
string or null | no | The keyword or audience, at most 120 characters. Empty or null for none. |
utm_content |
string or null | no | Tells two links of one campaign apart, at most 120 characters. Empty or null for none. |
coupon_code |
string or null | no | A coupon of this organization that the link applies, as ?coupon=. It must exist. Empty or null for none. |
notes |
string or null | no | A note for your team, at most 500 characters. Empty or null for none. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read what each campaign brought in
Section titled Read what each campaign brought inGET /api/v1/orgs/{org_slug}/staff/marketing/campaigns/results
What every saved campaign brought in over a period, and the campaign words no saved campaign names.
Needs the Billing, Admin or Owner role. The period is from to to in the brand's time zone, the last 30
days when left out, and at most 366 days. A campaign owns the visits, sign-ups and orders whose
utm_campaign is its own, ignoring capitals. The figures are the acquisition report's: a visit is a stored
session with bots left out, a sign-up is a customer whose last touch named the campaign, an order is a paid
order that is not free, and revenue_minor is the invoice total without tax in currency's minor units.
Orders and revenue are counted in one currency and never added across currencies: currencies names every
currency with an order in the period. conversion_rate_bp is orders over visits in basis points, so 123 is
1.23 percent. visits_complete is false when the period starts more than 180 days ago, because sessions are
kept for 180 days. unmatched lists the campaign words of the period that no saved campaign names, the
biggest first, at most limit.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
from |
query | string (date) or null | no | First day of the period, YYYY-MM-DD, in the brand's time zone. Left out, 29 days before the last day, so the period is the last 30 days. A period is at most 366 days. |
to |
query | string (date) or null | no | Last day of the period, YYYY-MM-DD, in the brand's time zone. Left out, today. |
currency |
query | string or null | no | A three letter currency code. Orders and revenue are counted in this one currency and never added across currencies. Left out, the currency with the most revenue in the period, else the brand's own. |
limit |
query | integer | no | Campaign words in unmatched, 1 to 200. Left out, 20. The saved campaigns are always all listed. Default: 20. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Change or archive a campaign link
Section titled Change or archive a campaign linkPATCH /api/v1/orgs/{org_slug}/staff/marketing/campaigns/{campaign_id}
Change the fields of a campaign that were sent, or archive it with archived, and answer it.
Needs the Billing, Admin or Owner role. Only the fields sent are checked and changed, by the rules of a
save. A null or empty utm_term, utm_content, coupon_code or notes clears it. Saving what is
already there changes nothing and writes no audit entry. A change is recorded as campaign.updated with
the names of the fields that changed. A campaign of another organization answers 404.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
campaign_id |
path | integer | yes |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name |
string or null | no | What you call the campaign, at most 120 characters. Each campaign in an organization has its own name, and two names that differ only in capitals count as one. |
base_path |
string or null | no | The page the link opens: a path on your storefront that starts with /, at most 400 characters, such as /pricing. It holds no host, scheme, fragment, backslash, space or control character, and at most one ?. A query in it is kept and the UTM words go after it. Left out when you create a campaign, it is /. |
utm_source |
string or null | no | Where the visit comes from, such as newsletter. At most 80 characters, with no &, =, #, ? or control character. |
utm_medium |
string or null | no | How the link is delivered, such as email. At most 80 characters, with the same limits as the source. |
utm_campaign |
string or null | no | The word the reports group by, at most 120 characters, with the same limits as the source. A visit or order whose campaign is this word belongs to the campaign, whatever its capitals. |
utm_term |
string or null | no | The keyword or audience, at most 120 characters. Empty or null for none. |
utm_content |
string or null | no | Tells two links of one campaign apart, at most 120 characters. Empty or null for none. |
coupon_code |
string or null | no | A coupon of this organization that the link applies, as ?coupon=. It must exist. Empty or null for none. |
notes |
string or null | no | A note for your team, at most 500 characters. Empty or null for none. |
archived |
boolean or null | no | true archives the campaign and false brings it back. An archived campaign keeps its link and its results. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Delete a campaign link
Section titled Delete a campaign linkDELETE /api/v1/orgs/{org_slug}/staff/marketing/campaigns/{campaign_id}
Delete a campaign link. The visits and orders that carried its words stay in the reports.
Needs the Billing, Admin or Owner role. Archive a campaign instead to keep its link and its results in the
list. A campaign of another organization answers 404. Recorded as campaign.deleted.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
campaign_id |
path | integer | yes |
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read what one campaign brought in
Section titled Read what one campaign brought inGET /api/v1/orgs/{org_slug}/staff/marketing/campaigns/{campaign_id}/results
What one campaign brought in over a period and over the period before it.
Needs the Billing, Admin or Owner role. The figures and their definitions are those of GET results.
totals holds visits, signups, orders, new_customers, revenue_minor and conversion_rate_bp, and
totals.previous holds the same for the comparison period, or null when compare is none. A campaign of
another organization answers 404.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
campaign_id |
path | integer | yes | |
org_slug |
path | string | yes | |
from |
query | string (date) or null | no | First day of the period, YYYY-MM-DD, in the brand's time zone. Left out, 29 days before the last day, so the period is the last 30 days. A period is at most 366 days. |
to |
query | string (date) or null | no | Last day of the period, YYYY-MM-DD, in the brand's time zone. Left out, today. |
compare |
query | string or null | no | previous (the default) sets every total against the same number of days just before the period, and a calendar month against the month before it. none leaves the comparison out. Default: previous. |
currency |
query | string or null | no | A three letter currency code. Orders and revenue are counted in this one currency and never added across currencies. Left out, the currency with the most revenue in the period, else the brand's own. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
List the ad platforms purchases are sent to, and how each is doing
Section titled List the ad platforms purchases are sent to, and how each is doingGET /api/v1/orgs/{org_slug}/staff/marketing/conversions
Every ad platform the organization can send purchases to, with its settings and how it is doing.
Needs the Admin or Owner role. There is one entry for each of ga4, google_ads, meta_capi,
tiktok_events, microsoft_ads, reddit_ads and x_ads, whether or not it was ever set up.
An entry has enabled, test_mode, config (the settings that are not secret), secret_set
(whether a secret is saved; the secret is never answered), fields and secret (what a form for
the kind asks), last_delivery (the newest event the kind was sent, with its status) and
coverage: orders is how many first purchases were paid in the last 30 days, sent how many
of them the kind was sent, and rate is sent over orders (null with no orders).
Microsoft Ads has no secret. Its entry has feed_url_masked, the address of its file with the token
hidden, and when Microsoft Advertising last fetched it.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read what each platform was sent, and why anything was not
Section titled Read what each platform was sent, and why anything was notGET /api/v1/orgs/{org_slug}/staff/marketing/conversions/deliveries
What each platform was sent, newest first, and why anything was not.
Needs the Admin or Owner role. Every row is one event for one platform: event is purchase
(a first purchase), renewal, upgrade, free_server, sign_up, refund or
chargeback; status is sent, skipped (error says why: the buyer did not allow
marketing, the platform has no such event, renewals are off) or failed (http_status and
error hold the platform's answer, and a timeout or a server error is tried again, three
attempts in all). invoice names the invoice the row belongs to. Filter by kind, status
and invoice_number; count is the total that match.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
kind |
query | string or null | no | ga4, google_ads, meta_capi, tiktok_events, microsoft_ads, reddit_ads or x_ads. |
status |
query | string or null | no | sent, failed or skipped. |
invoice_number |
query | string or null | no | Only the deliveries of this invoice, its refunds and its chargebacks. |
limit |
query | integer | no | Default: 50. |
offset |
query | integer | no | Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Turn an ad platform on or off and change its settings
Section titled Turn an ad platform on or off and change its settingsPUT /api/v1/orgs/{org_slug}/staff/marketing/conversions/{kind}
Turn a platform on or off, set its test mode, change its settings, set or clear its secret.
Needs the Admin or Owner role. Send only what changes. config keys replace the saved ones and a
null or empty string removes one; labels (Google Ads) and events (X) replace the whole map.
secret is write only: it is sealed, never answered and never written to the audit log, and an
empty string clears it. X takes an object of consumer_key, consumer_secret, access_token
and access_token_secret. Google Ads and Microsoft Ads take no secret, and a secret for them
answers 422. A value that does not fit, or a platform turned on without what it needs, answers 422
with detail, the sentence to show, and field, the input it belongs to. Every ID is checked
as the analytics and ad tags check theirs.
Turning Microsoft Ads on the first time makes the address of its file, and only that answer carries
the whole address in feed_url. Copy it into a schedule in Microsoft Advertising. Later answers
show it with the token hidden. The answer is {integration, changed, feed_url}. Each change is
recorded in the audit log without any secret.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
kind |
path | string | yes | ga4, google_ads, meta_capi, tiktok_events, microsoft_ads, reddit_ads or x_ads. |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
boolean or null | no | Turn the integration on or off. It needs its settings and secret first (422 names the first one missing). |
test_mode |
boolean or null | no | Send every event as a test: Meta and TikTok with the test event code, Google Analytics to its validation endpoint, Reddit with its test flag. Google Ads and X have no test mode. |
config |
object or null | no | Settings to change. A key replaces the stored one and null removes it. labels and events replace the whole map. |
secret |
string or object or null | no | The platform's secret. Write only: it is sealed and never answered, only secret_set. An empty string clears it. X takes an object of its four OAuth values. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Replace the token in the Microsoft Ads file address
Section titled Replace the token in the Microsoft Ads file addressPOST /api/v1/orgs/{org_slug}/staff/marketing/conversions/{kind}/rotate-feed-token
Replace the token in the Microsoft Ads file address, so the old address stops working.
Needs the Admin or Owner role. The answer is {integration, feed_url} and the only one that shows
the new address whole. Put it in the schedule in Microsoft Advertising; from now on the old address
answers 404. Purchases the file already listed stay listed. Answers 409 before Microsoft Ads was
first turned on, since that makes the first address.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
kind |
path | string | yes | microsoft_ads, the one platform that fetches a file from Coritan. |
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Send a made-up purchase to an ad platform in test mode
Section titled Send a made-up purchase to an ad platform in test modePOST /api/v1/orgs/{org_slug}/staff/marketing/conversions/{kind}/test
Send one made-up purchase to a platform in test mode and answer what the platform said.
Needs the Admin or Owner role. The event is for one currency unit of a product called "Test
product" and carries nothing about a person. Meta and TikTok send their test event code, Google
Analytics its validation endpoint and Reddit its test flag, so nothing reaches live reporting. The
platform needs its settings and secret saved first (422 names the missing one). Google Ads and X have
no test mode, so a test would count as a real sale and answers 422, and Microsoft Ads fetches its
file and takes no events. At most ten test events an hour for each platform (429). The test is not
logged as a delivery and is not counted in coverage. The answer is {kind, event, status, ok, http_status, error, event_id}.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
kind |
path | string | yes | ga4, google_ads, meta_capi, tiktok_events, microsoft_ads, reddit_ads or x_ads. |
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
List the automatic email flows, with their settings and how many emails each sent
Section titled List the automatic email flows, with their settings and how many emails each sentGET /api/v1/orgs/{org_slug}/staff/marketing/flows
Every automatic email flow of the organization, whether or not it was ever turned on.
Needs the Admin or Owner role. There is one entry for each of unpaid_invoice, stuck_setup,
free_upgrade, winback, onboarding and review_invite. An entry has its label, kind
(service flows are about the customer's own order and need no marketing consent, marketing flows
go only to customers who agreed to marketing email) and description; enabled and config, the
saved settings with the defaults filled in; fields, what a form for the settings asks (key,
label, kind, default, min, max, hint); template_slugs, one for each step;
blocked, the sentence that says why the flow cannot send even when on (the review invitation needs a
saved Trustpilot review link), or null; and stats, how many emails are scheduled, sent,
skipped, failed or canceled and last_sent_at. Every flow is off until turned on. One customer
gets at most one flow email in 3 days, from any flow.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read the log of flow emails, newest first
Section titled Read the log of flow emails, newest firstGET /api/v1/orgs/{org_slug}/staff/marketing/flows/messages
Every email a flow scheduled, newest first, with what became of it.
Needs the Admin or Owner role. A row has flow, step, status, email, scheduled_at,
sent_at, customer_id and error. scheduled waits for the next pass (at most ten minutes),
sent went to the mail server, skipped was left out on purpose (error says why: the address
unsubscribed, the account is not active, another flow email went to the customer in the last 3 days, or
it was due more than a day ago), canceled lost its reason before it went (the invoice was paid, the
server is running, the customer withdrew consent, the flow was turned off) and failed was refused by
the mail server. count is the total that match, before limit and offset.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
flow |
query | string or null | no | Only this flow: unpaid_invoice, stuck_setup, free_upgrade, winback, onboarding or review_invite. |
status |
query | string or null | no | Only this status: scheduled, sent, skipped, failed or canceled. |
limit |
query | integer | no | How many rows to answer, 1 to 200. Default: 50. |
offset |
query | integer | no | How many rows to skip. Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Turn an email flow on or off and change its settings
Section titled Turn an email flow on or off and change its settingsPUT /api/v1/orgs/{org_slug}/staff/marketing/flows/{key}
Turn a flow on or off and change its settings. Send only what changes.
Needs the Admin or Owner role. config keys replace the saved ones; GET lists them in fields with
their ranges. coupon_code (win-back) takes a coupon of the organization, or null to remove it. A value
that does not fit answers 422 with detail, the sentence to show, and field, the input it belongs
to (config.after_days, or enabled for the review invitation without a saved Trustpilot review
link), and changes nothing. The answer is {flow, changed}: the flow as GET lists it and the names that
differ. Saving what is already saved changes nothing and writes no audit entry. A change is audited as
flows.updated with the settings before and after. A flow starts mailing at its next pass, within ten
minutes, and only customers who qualify from then on.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
key |
path | string | yes | The flow: unpaid_invoice, stuck_setup, free_upgrade, winback, onboarding or review_invite. |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
boolean or null | no | Turn the flow on or off. The review invitation can only be turned on once a Trustpilot review link is saved and on (422 otherwise). |
config |
object or null | no | The flow's settings to change, by name, as GET lists them in fields. A value outside its range answers 422 and changes nothing. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Send a flow's sample email to yourself
Section titled Send a flow's sample email to yourselfPOST /api/v1/orgs/{org_slug}/staff/marketing/flows/{key}/test
Send the flow's email, filled with made-up facts, to the address of the signed-in member.
Needs the Admin or Owner role. The test goes out whether or not the flow is on, as service mail, with the
brand's own links and the flow's coupon code, and writes nothing to the flow log. An address on the
organization's unsubscribe list gets nothing (409). step picks the email of a flow with two (422 for a
step the flow lacks). The member needs an address on their account (400). At most ten test emails an hour
for one member (429). The answer is {sent, to, flow, step, template}; 502 when the mail server did not
accept it. Audited as flows.test_sent.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
key |
path | string | yes | The flow: unpaid_invoice, stuck_setup, free_upgrade, winback, onboarding or review_invite. |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json
| Field | Type | Required | Description |
|---|---|---|---|
step |
string or null | no | Which email of the flow to send, 1 or 2. The default is 1. Only unpaid_invoice and onboarding have a second step. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
List the organization's referrals and what the program has paid
Section titled List the organization's referrals and what the program has paidGET /api/v1/orgs/{org_slug}/staff/marketing/referrals
Every referral of the organization, newest first, and the program's totals.
Needs the Admin or Owner role. A referral is one referred customer: their first paid invoice started it.
status is qualified while it waits out its hold (hold_until), credited once the wallet credit
is paid, and void when a rule refused it (void_reason says which, or holds the reason staff gave).
referrer and referee name the two customers, code the code that was used and invoice the
invoice that started it. reward_amount is what the referrer is paid and referee_reward_amount the
welcome credit, both in wallet dollars (currency). count is how many referrals match the filters.
totals covers the whole program and ignores the filters: the number of referrals in each status,
credited_amount paid out so far and owed_amount for the open ones.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
status |
query | string or null | no | pending, qualified, credited or void. |
q |
query | string or null | no | Part of either customer's email address, without regard to capitals. |
limit |
query | integer | no | Referrals to return, newest first. At most 200. Default: 50. |
offset |
query | integer | no | Referrals to skip. Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
List referral codes, customers' and partners'
Section titled List referral codes, customers' and partners'GET /api/v1/orgs/{org_slug}/staff/marketing/referrals/codes
The organization's referral codes, newest first, each with how many referrals it started.
Needs the Admin or Owner role. A customer code is made for each customer the first time they open their
referral page. A partner code is made by your team and pays commission_bp of the referred customer's
first invoice. referrals on a code is {total, credited, earned}: the referrals it started, how many
were paid, and what they paid the owner in wallet dollars.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
kind |
query | string or null | no | customer or partner. |
active |
query | boolean or null | no | true for codes that work, false for stopped ones. |
q |
query | string or null | no | Part of the code, its label or the owner's email address. |
limit |
query | integer | no | Codes to return, newest first. At most 200. Default: 50. |
offset |
query | integer | no | Codes to skip. Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Make a partner code for a customer
Section titled Make a partner code for a customerPOST /api/v1/orgs/{org_slug}/staff/marketing/referrals/codes
Make a partner code that pays a share of the first invoice of every customer it brings.
Needs the Admin or Owner role. Name the owner with customer_id or email: an active customer of this
organization. commission_bp (1 to 5000, 100 is 1 percent) is the share of the referred customer's first
invoice, without tax, paid into the owner's wallet once the hold has passed. code is optional: 3 to 40
letters, digits, hyphens or underscores, and without regard to capitals it must not be in use (409). Left out,
we make an 8 character code. At most 30 codes an hour. Answers 422 with detail and field for a value
that does not fit. The code is recorded in the audit log as referral_code.created.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
customer_id |
boolean or integer or string or null | no | The customer who owns the code. Give this or email. |
email |
string or null | no | The email address of the customer who owns the code. Give this or customer_id. |
code |
string or null | no | The code, 3 to 40 letters, digits, hyphens or underscores. Left out, we make an 8 character one. |
commission_bp |
boolean or integer or string or null | no | The share of the referred customer's first invoice, without tax, the owner is paid, in basis points: 1 to 5000 (100 is 1 percent). |
label |
string or null | no | A note for your team, such as the partner's name. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
201 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Stop or restart a code, or change a partner's commission or label
Section titled Stop or restart a code, or change a partner's commission or labelPATCH /api/v1/orgs/{org_slug}/staff/marketing/referrals/codes/{code_id}
Change whether a code works, a partner code's commission, or its label. The code itself never changes.
Needs the Admin or Owner role. active: false stops the code from starting new referrals; referrals it
already started still pay. commission_bp (1 to 5000) is for a partner code only: a customer's code pays
the program's reward amount. label is a note for your team, and null or an empty string removes it. Send
only what changes. Answers 404 for a code of another organization and 422 with detail and field for a
value that does not fit. A change is recorded as referral_code.updated with the values before and after.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
code_id |
path | integer | yes | The code's id. |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
active |
boolean or null | no | false stops the code from starting new referrals. Referrals it already has still pay. |
commission_bp |
boolean or integer or string or null | no | A partner code's share in basis points: 1 to 5000. |
label |
string or null | no | A note for your team. null or an empty string removes it. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Void a referral that has not been paid
Section titled Void a referral that has not been paidPOST /api/v1/orgs/{org_slug}/staff/marketing/referrals/{referral_id}/void
Void a referral so it is never paid. Only a pending or qualified referral can be voided.
Needs the Admin or Owner role. reason is required, 1 to 120 characters, and is kept as the referral's
void_reason. A referral that is already credited or void answers 409, and money already paid is not
taken back. Answers 404 for a referral of another organization. At most 60 an hour. Recorded in the audit log
as referral.voided with the reason.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
referral_id |
path | integer | yes | The referral's id. |
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
reason |
string or null | no | Why the referral is void, 1 to 120 characters. It is kept with the referral. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Read the Trustpilot review settings and how the invitations are doing
Section titled Read the Trustpilot review settings and how the invitations are doingGET /api/v1/orgs/{org_slug}/staff/marketing/reviews
The Trustpilot review settings, and how the review invitation emails are doing.
Needs the Admin or Owner role. enabled is whether the storefront asks signed-in customers for a review,
review_url the Trustpilot link it opens (null for none), min_account_age_days how old an account is
before it asks, and dismiss_days how long it stays quiet after a customer closes the prompt. The
invitation is the email flow review_invite, which uses the same link. invitations holds enabled
(the flow's own switch), the number of its messages scheduled, sent, skipped and failed (all 0
until the flow has run) and last_sent_at.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Change the Trustpilot review settings
Section titled Change the Trustpilot review settingsPUT /api/v1/orgs/{org_slug}/staff/marketing/reviews
Change the review settings. Send only what changes.
Needs the Admin or Owner role. review_url must start with https:// and be on trustpilot.com, at most
500 characters, and the prompt cannot be turned on without one. min_account_age_days is 0 to 365 and
dismiss_days 1 to 365. A value that does not fit answers 422 with detail, the sentence to show, and
field, the setting it belongs to. The answer is the one GET gives, with changed listing the settings
that differ from before. Saving what is already saved changes nothing and writes no audit entry. A change
is recorded as reviews.updated, and the storefront applies it to new page loads within a minute.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
boolean or null | no | Turn the review prompt on or off. It needs review_url, and an on switch with no link answers 422. |
review_url |
string or null | no | Your Trustpilot review link. It starts with https:// and is on trustpilot.com, at most 500 characters. Null or empty removes it. |
min_account_age_days |
integer or null | no | How many days old an account is before the prompt asks, 0 to 365. The default is 1. |
dismiss_days |
integer or null | no | How many days the prompt stays quiet after a customer closes it, 1 to 365. The default is 30. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
List the newsletter's leads and count who can be mailed
Section titled List the newsletter's leads and count who can be mailedGET /api/v1/orgs/{org_slug}/staff/marketing/subscribers
The addresses visitors gave the storefront's newsletter form, newest first.
Needs the Admin or Owner role. Every row is one address: id, email, source (where it was
collected), consent (whether the visitor agreed to email), consent_text (the words they agreed
to), customer_id (the customer with that address, if there is one), suppressed (true when the
address is on the suppression list and gets no marketing email whatever its consent says) and
created_at. Filter by part of the address with q, by source and by consent; total is
every lead the filters match. counts covers the whole organization: leads (every lead),
consenting_customers (active customers who agreed to marketing email) and suppressed (addresses
on the suppression list).
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
q |
query | string or null | no | Part of the address. |
source |
query | string or null | no | Only leads that came from this source. |
consent |
query | boolean or null | no | true for leads who agreed to email, false for the rest. |
limit |
query | integer | no | Default: 50. |
offset |
query | integer | no | Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Download the addresses that can be mailed as a CSV file
Section titled Download the addresses that can be mailed as a CSV fileGET /api/v1/orgs/{org_slug}/staff/marketing/subscribers/export.csv
Every address the organization may send marketing email to, as a CSV file.
Needs the Admin or Owner role. The columns are email, source, consent, kind (lead or
customer) and created_at. The file lists leads who agreed to email and active customers who
agreed to marketing email, once for each address (an address that is both is a lead). It never lists an
address on the suppression list. A cell that starts with =, +, - or @ begins with an
apostrophe so a spreadsheet does not run it. A file holds at most 100,000 rows and the answer's
X-Export-Truncated: true header says when a list was longer. At most 12 exports an hour (429). Every
export is audited as subscribers.exported before the file is answered.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
List the addresses that get no marketing email
Section titled List the addresses that get no marketing emailGET /api/v1/orgs/{org_slug}/staff/marketing/subscribers/suppressions
The organization's suppression list, newest first.
Needs the Admin or Owner role. An address on the list gets no marketing email, whatever its owner's
consent says. Every row has id, email, reason (unsubscribed, bounced,
complained or manual), source (link, account, console or api) and
created_at. Filter by part of the address with q; total is every row that matches. The list
belongs to this organization alone: an address another brand suppressed is not here.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
org_slug |
path | string | yes | |
q |
query | string or null | no | Part of the address. |
limit |
query | integer | no | Default: 50. |
offset |
query | integer | no | Default: 0. |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Add an address to the suppression list
Section titled Add an address to the suppression listPOST /api/v1/orgs/{org_slug}/staff/marketing/subscribers/suppressions
Stop marketing email to one address.
Needs the Admin or Owner role. reason must be manual (the other reasons are set by an
unsubscribe, a bounce or a complaint). The row's source is console. Adding an address cancels the
flow emails still waiting for it, takes marketing consent back from a customer with that address and
marks a lead with it as not consenting. An address already on the list stays as it was and the answer
has added: false. A bad address or reason answers 422 {"detail", "field"}. The answer is
{suppression, added} and a new entry is audited as suppression.added.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | yes | The address that gets no marketing email. |
reason |
string | no | Why it is on the list. A person adds an address with the reason "manual". |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Take an address off the suppression list
Section titled Take an address off the suppression listDELETE /api/v1/orgs/{org_slug}/staff/marketing/subscribers/suppressions/{suppression_id}
Let marketing email reach an address again.
Needs the Admin or Owner role. This removes the row only: it does not give anyone's consent back, so a
customer or lead who withdrew still has to agree again before they get marketing email. 404 for an id
that is not on this organization's list. Audited as suppression.lifted.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
suppression_id |
path | integer | yes | The id of a row of the suppression list. |
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Delete a lead
Section titled Delete a leadDELETE /api/v1/orgs/{org_slug}/staff/marketing/subscribers/{lead_id}
Delete one lead for good.
Needs the Admin or Owner role. Only the lead row goes: the customer with that address, their consent
and the suppression list are not touched, so an address that unsubscribed stays unsubscribed. 404 for an
id that is not this organization's lead. Audited as subscriber.deleted with the lead's id and
source, never its address.
Parameters
Section titled Parameters| Name | In | Type | Required | Description |
|---|---|---|---|---|
lead_id |
path | integer | yes | The id of a lead. |
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
The tags the storefront loads, and what an editor needs to draw them
Section titled The tags the storefront loads, and what an editor needs to draw themGET /api/v1/orgs/{org_slug}/staff/marketing/tags
The tags the storefront loads, and what an editor needs to draw them.
Needs the Admin or Owner role. tags holds the platforms that are on, each
with the public ids saved for it; a platform with no id is off and absent.
kinds lists every platform with its label, a sentence about it and its
fields (key, label, hint, pattern, example), so a form can
be drawn from it. consent says whether the storefront shows its cookie
banner and which page the banner links to. legacy_google_analytics is true
while the Google Analytics ID shown still comes from the older single setting,
which the next save replaces.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |
Replace the tags the storefront loads with the ones sent
Section titled Replace the tags the storefront loads with the ones sentPUT /api/v1/orgs/{org_slug}/staff/marketing/tags
Replace the tags the storefront loads with the ones sent.
Needs the Admin or Owner role. tags is the whole object: a platform left
out is turned off. Each id is trimmed and checked against the shape its
platform uses, and a platform with no id is left out. The answer is the one
GET gives, with changed listing the platforms that differ from before.
A bad id answers 422 with detail, the sentence to show, and field, the
input it belongs to (meta.pixel_id). Saving what is already stored changes
nothing. Every change is recorded in the audit log with the ids before and
after. Tags apply to new page loads within a minute.
Parameters
Section titled Parameters| Name | In | Type | Required |
|---|---|---|---|
org_slug |
path | string | yes |
Request body
Section titled Request bodyapplication/json (required)
| Field | Type | Required |
|---|---|---|
tags |
Tags | yes |
Responses
Section titled Responses| Status | Meaning |
|---|---|
200 |
Success. |
422 |
The request is not valid. detail lists each problem. |