Download OpenAPI specification:
Access your Reacher affiliate data programmatically. Use your API key in the x-api-key header and shop ID in the x-shop-id header.
Returns all active shops accessible to this API key. Use the returned shop_id values in the x-shop-id header for other endpoints.
{- "data": [
- {
- "shop_id": 0,
- "shop_name": "string",
- "region": "string",
- "currency": "string",
- "status": "string",
- "primary_category": "string"
}
]
}List affiliate creators for your shop with pagination, sorting, and filtering. GMV represents the creator's lifetime revenue for this shop. Data updates approximately every hour.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Status (string) or Status (null) (Status) | |
Creator Handle (string) or Creator Handle (null) (Creator Handle) | |
Min Shop Gmv (number) or Min Shop Gmv (null) (Min Shop Gmv) | |
Min Overall Gmv (number) or Min Overall Gmv (null) (Min Overall Gmv) | |
Min Videos (integer) or Min Videos (null) (Min Videos) | |
Min Followers (integer) or Min Followers (null) (Min Followers) | |
Group Id (string) or Group Id (null) (Group Id) | |
Array of Tags (strings) or Tags (null) (Tags) | |
Product Id (string) or Product Id (null) (Product Id) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "shop_gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "status": "string",
- "creator_handle": "string",
- "min_shop_gmv": 0,
- "min_overall_gmv": 0,
- "min_videos": 0,
- "min_followers": 0,
- "group_id": "string",
- "tags": [
- "string"
], - "product_id": "string"
}{- "data": [
- {
- "creator_handle": "string",
- "follower_count": 0,
- "status": "string",
- "shop_gmv": 0,
- "overall_gmv": 0,
- "overall_fulfillment_rate": 0,
- "shop_units_sold": 0,
- "shop_video_count": 0,
- "video_views": 0,
- "sample_received": 0,
- "commission_rate": 0,
- "est_commission": 0,
- "fulfillment_rate": 0,
- "tags": [
- "string"
], - "product_id": "string",
- "product_title": "string",
- "updated_at": "string",
- "created_at": "string"
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Top creators ranked by GMV earned within a specific date range. Unlike /creators/list (which shows lifetime GMV), this endpoint uses daily performance data and matches the dashboard's 'Top Creators' section exactly. Defaults to the last 30 days. Use this for period-specific rankings and reports.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Creator Handle (string) or Creator Handle (null) (Creator Handle) | |
Min Gmv (number) or Min Gmv (null) (Min Gmv) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "creator_handle": "string",
- "min_gmv": 0
}{- "data": [
- {
- "creator_id": "string",
- "creator_handle": "string",
- "gmv": 0,
- "units_sold": 0,
- "order_count": 0,
- "est_commission": 0,
- "follower_count": 0
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Four headline totals for the shop over a date window: creators added, affiliate GMV earned, videos posted, and orders placed. Runs the same aggregate query that backs the summary cards above the portal's My Creators table, over the same trailing-28-day default window (TikTok reporting day, GMT-7).
gmv_generated and video_posts are scoped to the shop's CRM-tracked creators, which makes them narrower than their whole-shop namesakes on POST /metrics/summary (gmv, videos_posted) — the two will not agree, by design.
Aggregates cover the whole shop — there is no filter parameter in v1. Defaults to the trailing 28 days. Requires a single shop.
No prior-period comparison is included; for a period-over-period delta, call twice with adjacent windows and subtract. Returns 503 when the aggregate times out — back off and retry rather than treating it as a failure.
Start Date (string) or Start Date (null) (Start Date) Window start (inclusive). Omit for a trailing 28-day window ending at end_date. | |
End Date (string) or End Date (null) (End Date) Window end (inclusive). Defaults to today. |
{- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "data": {
- "new_creators": 0,
- "gmv_generated": 0,
- "video_posts": 0,
- "orders": 0
}, - "currency": "string",
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}
}Daily time series for up to 100 named creators — affiliate GMV, video GMV, videos posted, video views, units sold, and commission. Backs sparklines and per-creator trend comparisons.
Every series is aligned positionally with the days axis and zero-filled, so index i of any array corresponds to days[i]. Creators with no activity in the window appear with all-zero arrays rather than being omitted; handles that don't exist in this shop are listed in unresolved_handles instead.
Defaults to the trailing 28 days. Requires a single shop.
| creator_handles required | Array of strings (Creator Handles) [ 1 .. 100 ] items Creator handles to fetch series for. Max 100 per call — this mirrors the internal per-page cap and keeps the response bounded. Handles that don't resolve in this shop are reported in |
Start Date (string) or Start Date (null) (Start Date) Window start (inclusive). Omit for a trailing 28-day window ending at end_date. | |
End Date (string) or End Date (null) (End Date) Window end (inclusive). Defaults to today. |
{- "creator_handles": [
- "string"
], - "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "data": {
- "property1": {
- "affiliate_gmv": [
- 0
], - "video_gmv": [
- 0
], - "videos_posted": [
- 0
], - "total_video_views": [
- 0
], - "units_sold": [
- 0
], - "commission": [
- 0
]
}, - "property2": {
- "affiliate_gmv": [
- 0
], - "video_gmv": [
- 0
], - "videos_posted": [
- 0
], - "total_video_views": [
- 0
], - "units_sold": [
- 0
], - "commission": [
- 0
]
}
}, - "days": [
- "string"
], - "unresolved_handles": [
- "string"
], - "currency": "string",
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}
}Distribution of creators by GMV tier (L0-L7). Matches the dashboard's 'Creators by Level' pie chart. Uses active creators from the date range (defaults to last 30 days). Pass start_date and end_date query params (YYYY-MM-DD) to customize the window. L0=$0, L1=<$5k, L2=$5k-$25k, L3=$25k-$60k, L4=$60k-$150k, L5=$150k-$400k, L6=$400k-$1M, L7=>$1M.
Start Date (string) or Start Date (null) (Start Date) Start date (YYYY-MM-DD). Defaults to 30 days ago. | |
End Date (string) or End Date (null) (End Date) End date (YYYY-MM-DD). Defaults to the shop's newest settled day. |
nullGet detailed information for a single creator, including groups, products, and latest 10 videos (for full video list, use POST /creators/{creator_handle}/videos).
| creator_handle required | string (Creator Handle) |
{- "data": {
- "creator_handle": "string",
- "follower_count": 0,
- "status": "string",
- "shop_gmv": 0,
- "overall_gmv": 0,
- "overall_fulfillment_rate": 0,
- "shop_units_sold": 0,
- "shop_video_count": 0,
- "video_views": 0,
- "sample_received": 0,
- "commission_rate": 0,
- "est_commission": 0,
- "fulfillment_rate": 0,
- "tags": [
- "string"
], - "product_id": "string",
- "product_title": "string",
- "updated_at": "string",
- "created_at": "string"
}, - "groups": [ ],
- "products": [ ],
- "videos": [ ],
- "currency": "string"
}Paginated list of videos by this creator in your shop.
| creator_handle required | string (Creator Handle) |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "video_gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "data": [
- {
- "video_id": "string",
- "title": "string",
- "video_url": "string",
- "creator_handle": "string",
- "product_id": "string",
- "product_name": "string",
- "views": 0,
- "like_count": 0,
- "comment_count": 0,
- "share_count": 0,
- "units_sold": 0,
- "video_gmv": 0,
- "posted_date": "string"
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Products this creator is affiliated with in your shop.
| creator_handle required | string (Creator Handle) |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
{- "page": 1,
- "page_size": 50
}{- "data": [
- {
- "product_id": "string",
- "product_title": "string",
- "commission_rate": 0,
- "shop_units_sold": 0,
- "shop_gmv": 0,
- "status": "string"
}
], - "currency": "string",
- "pagination": null,
- "shops_queried": [
- "string"
]
}Product performance metrics aggregated over a date range. Defaults to the last 7 days if no dates are specified. Data is typically 2-3 days behind the current date. Each product also carries its TikTok Seller Center per-product metrics as sc_* fields: all-channel GMV with its per-channel breakdown (affiliate, seller video, seller live, product card, shop tab), plus orders, units sold, customers, impressions, clicks, CTR, conversion, AOV, GMV per 1,000 impressions, add-to-cart, and refunds. The sc_* fields are null for products not yet on the Seller Center sync.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Product Name (string) or Product Name (null) (Product Name) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "product_name": "string"
}{- "data": [
- {
- "product_id": "string",
- "product_name": "string",
- "gmv": 0,
- "units_sold": 0,
- "refund_units": 0,
- "video_count": 0,
- "sample_count": 0,
- "live_count": 0,
- "est_commission": 0,
- "product_status": "string",
- "sc_total_gmv": 0,
- "sc_orders": 0,
- "sc_units_sold": 0,
- "sc_customers": 0,
- "sc_aov": 0,
- "sc_impressions": 0,
- "sc_clicks": 0,
- "sc_ctr": 0,
- "sc_conversion": 0,
- "sc_gmv_per_1k_impr": 0,
- "sc_add_to_cart": 0,
- "sc_affiliate_gmv": 0,
- "sc_seller_video_gmv": 0,
- "sc_seller_live_gmv": 0,
- "sc_product_card_gmv": 0,
- "sc_shop_tab_gmv": 0,
- "sc_refunds": 0
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Creators affiliated with this product.
| product_id required | string (Product Id) |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
{- "page": 1,
- "page_size": 50
}{- "data": [
- {
- "creator_handle": "string",
- "follower_count": 0,
- "commission_rate": 0,
- "gmv": 0
}
], - "currency": "string",
- "pagination": null,
- "shops_queried": [
- "string"
]
}Videos featuring this product.
| product_id required | string (Product Id) |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "video_gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "data": [
- {
- "video_id": "string",
- "title": "string",
- "video_url": "string",
- "creator_handle": "string",
- "product_id": "string",
- "product_name": "string",
- "views": 0,
- "like_count": 0,
- "comment_count": 0,
- "share_count": 0,
- "units_sold": 0,
- "video_gmv": 0,
- "posted_date": "string"
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Affiliate videos and their performance metrics. Values represent lifetime totals per video (total views, total GMV, etc.). Data can be up to three days stale, given the delay in affiliate center.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Creator Id (string) or Creator Id (null) (Creator Id) | |
Creator Handle (string) or Creator Handle (null) (Creator Handle) | |
Product Id (string) or Product Id (null) (Product Id) | |
Min Gmv (number) or Min Gmv (null) (Min Gmv) | |
Min Views (integer) or Min Views (null) (Min Views) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "video_gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "creator_id": "string",
- "creator_handle": "string",
- "product_id": "string",
- "min_gmv": 0,
- "min_views": 0
}{- "data": [
- {
- "video_id": "string",
- "title": "string",
- "video_url": "string",
- "creator_handle": "string",
- "product_id": "string",
- "product_name": "string",
- "views": 0,
- "like_count": 0,
- "comment_count": 0,
- "share_count": 0,
- "units_sold": 0,
- "video_gmv": 0,
- "posted_date": "string"
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}The shop's top videos ranked by GMV earned in the date range (defaults to the last 30 days, same ranking as /videos/performance), each enriched with the AI creative breakdown: hook, sell points, product niche, shot style, and videography. Use this to analyze WHY the top videos perform — not just how much they earned. Videos that haven't been analyzed yet keep their metrics and list the unavailable breakdown fields in creative.missing_fields; render those as 'not analyzed' rather than blank. Multi-shop requests (x-shop-id: all or comma-separated) mirror /videos/performance's semantics: one ranking across shops with a single top-level currency (USD fallback) — use a single shop when per-shop currency precision matters.
| limit | integer (Limit) [ 1 .. 50 ] Default: 10 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) |
{- "limit": 10,
- "sort_by": "video_gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "data": [
- {
- "video_id": "string",
- "title": "string",
- "creator_handle": "string",
- "video_gmv": 0,
- "views": 0,
- "like_count": 0,
- "comment_count": 0,
- "order_count": 0,
- "posted_date": "string",
- "rank": 0,
- "creative": {
- "analyzed": true,
- "hook": {
- "text": "string",
- "classification": "string",
- "reasoning": "string"
}, - "sell_points": [
- "string"
], - "product_niche": "string",
- "shot_style": [
- "string"
], - "videography": {
- "locations": [
- "string"
], - "lighting": [
- "string"
], - "product_showcase": [
- "string"
], - "notes": "string"
}, - "missing_fields": [
- "string"
]
}
}
], - "currency": "string",
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "coverage": {
- "videos_returned": 0,
- "with_creative_analysis": 0
}, - "total_count": 0,
- "message": "string",
- "shops_queried": [
- "string"
]
}Top videos ranked by GMV or views earned within a specific date range. Unlike /videos/list (which shows lifetime totals), this endpoint uses daily performance data and matches the dashboard's 'Top Videos' section exactly. Defaults to the last 30 days. Use this for period-specific rankings, trend analysis, and correlating video performance with product sales.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Creator Handle (string) or Creator Handle (null) (Creator Handle) | |
Min Gmv (number) or Min Gmv (null) (Min Gmv) | |
Min Views (integer) or Min Views (null) (Min Views) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "video_gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "creator_handle": "string",
- "min_gmv": 0,
- "min_views": 0
}{- "data": [
- {
- "video_id": "string",
- "title": "string",
- "creator_handle": "string",
- "video_gmv": 0,
- "views": 0,
- "like_count": 0,
- "comment_count": 0,
- "order_count": 0,
- "posted_date": "string"
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Track sample requests from creators in your shop. Shows only sample-related statuses. Data updates approximately every hour.
Each row includes the requesting creator's bio, categories, and email (sourced from the same regional creators table the AI Creator Search API reads), so consumers can score sample requests on brand/niche fit without a second API call. These fields are null when the creator has no row in the regional creators table.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Status (string) or Status (null) (Status) | |
Creator Handle (string) or Creator Handle (null) (Creator Handle) | |
Product Id (string) or Product Id (null) (Product Id) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "updated_at",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "status": "string",
- "creator_handle": "string",
- "product_id": "string"
}{- "data": [
- {
- "creator_handle": "string",
- "product_id": "string",
- "product_title": "string",
- "status": "string",
- "gmv": 0,
- "units_sold": 0,
- "sample_received": 0,
- "updated_at": "string",
- "bio": "string",
- "categories": [
- "string"
], - "email": "string"
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Sample performance breakdown by product. Shows requests, approvals, and GMV per product. Data can be up to three days stale, given the delay in affiliate center.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) |
{- "page": 1,
- "page_size": 50,
- "sort_by": "total_requests",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "data": [
- {
- "product_id": "string",
- "product_name": "string",
- "total_requests": 0,
- "approved": 0,
- "sample_gmv": 0,
- "videos_from_samples": 0
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
]
}Your automations with performance and outreach metrics. Includes creators reached, sample requests, videos posted, and GMV. reply_rate is populated for Running, Stopped, and Completed automations.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 50 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_dir | string (Sort Dir) Default: "desc" Enum: "asc" "desc" |
Start Date (string) or Start Date (null) (Start Date) Inclusive window start (YYYY-MM-DD). When supplied (alone or with | |
End Date (string) or End Date (null) (End Date) Inclusive window end (YYYY-MM-DD). When supplied (alone or with | |
Automation Type (string) or Automation Type (null) (Automation Type) | |
Status (string) or Status (null) (Status) | |
Array of Created Via (strings) or Created Via (null) (Created Via) Include only automations created by these surfaces. Common values: | |
Array of Exclude Created Via (strings) or Exclude Created Via (null) (Exclude Created Via) Exclude automations created by these surfaces. Applied after |
{- "page": 1,
- "page_size": 50,
- "sort_by": "gmv",
- "sort_dir": "asc",
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "automation_type": "string",
- "status": "string",
- "created_via": [
- "string"
], - "exclude_created_via": [
- "string"
]
}{- "data": [
- {
- "automation_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "status": "string",
- "status_message": "string",
- "gmv": 0,
- "sample_requests": 0,
- "accepted_requests": 0,
- "videos_posted": 0,
- "videos_converted": 0,
- "creators_reached": 0,
- "dm_response_count": 0,
- "reply_rate": 0,
- "skipped": 0,
- "total_creators": 0,
- "creators_remaining": 0,
- "created_at": "string",
- "completed_at": "string",
- "created_via": "string"
}
], - "currency": "string",
- "pagination": null,
- "date_range": {
- "start_date": "string",
- "end_date": "string"
}, - "shops_queried": [
- "string"
], - "aggregate": {
- "creators_reached": 0,
- "tc_invites": 0,
- "tc_invites_creator_count": 0,
- "creators_messaged": 0,
- "emails_sent": 0,
- "sample_request": 0,
- "sample_approved": 0,
- "videos_posted": 0,
- "videos_converted": 0,
- "spark_codes": 0,
- "added_showcase_affiliates": 0,
- "accepted_tc_count": 0,
- "tc_showcase_creator_count": 0,
- "tc_content_creator_count": 0,
- "tc_acceptance_rate": 0
}
}Returns the filter options (categories, GMV ranges, follower segments, engagement / view tiers, content-style options, etc.) valid for the given shop region. Use the response to drive filter dropdowns or to validate creators_to_include.filters values before submitting a create request.
Region differences:
£ for UK, $ for US, € for EU regions, R$ for BR, etc.).Supported regions: US, UK, IE, MX, DE, FR, ES, BR, IT, GLOBAL (alias for US).
| shop_region required | string (Shop Region) |
nullCurrent outreach send-capacity for a single shop, so callers can pre-check before sending TC invites / DMs and schedule retries when capacity frees.
Two independent limits govern outreach:
daily_window_resets_at). daily_creators_used counts actual sends only (skipped/creator_not_found invites do not count). The daily ceiling is plan/TikTok-dependent and is not returned as a single number; daily_limit_throttled flags when the shop is currently paused by it.weekly_limit_throttled flags when paused by it; if true, retry next week.The daily pool is shared between the automation engine and direct POST /target-collabs invites. Requires a single shop.
{- "shop_id": 0,
- "daily_creators_used": 0,
- "daily_window_resets_at": "string",
- "concurrent_automations_running": 0,
- "max_concurrent_automations": 0,
- "daily_limit_throttled": true,
- "weekly_limit_throttled": true
}Detailed automation data with performance metrics.
| automation_id required | integer (Automation Id) |
{- "data": {
- "automation_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "status": "string",
- "status_message": "string",
- "gmv": 0,
- "sample_requests": 0,
- "accepted_requests": 0,
- "videos_posted": 0,
- "videos_converted": 0,
- "creators_reached": 0,
- "dm_response_count": 0,
- "reply_rate": 0,
- "skipped": 0,
- "total_creators": 0,
- "creators_remaining": 0,
- "created_at": "string",
- "completed_at": "string",
- "created_via": "string"
}, - "creators_remaining": 0,
- "currency": "string"
}Partial update across all 4 types. Cannot change automation_type, shop, lifecycle state, or system fields. Idempotency-Key optional; X-Dry-Run: true supported.
| automation_id required | integer (Automation Id) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
Automation Name (string) or Automation Name (null) (Automation Name) | |
AutomationSchedule (object) or null | |
CreatorsToInclude (object) or null | |
CreatorsToExclude (object) or null | |
Array of Messages (objects) or Messages (null) (Messages) Replace the initial-outreach addon set. ALL items are sent immediately together when the automation engages a creator. Pass | |
Array of Follow Ups (objects) or Follow Ups (null) (Follow Ups) Replace the delayed follow-up sequence. Pass | |
TargetCollabPatchPayload (object) or null Partial update for the TC-specific config. Send only the keys you want to change — supported sub-keys mirror | |
DmConfigPatchPayload (object) or null Partial update for the DM-specific config. Currently supports | |
SampleRequestPatchPayload (object) or null Partial update for the sample-request config. Send only the keys you want to change — supported sub-keys mirror | |
Ai Enabled (boolean) or Ai Enabled (null) (Ai Enabled) | |
Is Evergreen (boolean) or Is Evergreen (null) (Is Evergreen) | |
End Date (string) or End Date (null) (End Date) | |
Business Hours Timezone (string) or Business Hours Timezone (null) (Business Hours Timezone) Set or change the 9am–9pm send-window timezone (CORE-3031). Pass an IANA name to enable, or the empty string | |
Email Sent Per Day (integer) or Email Sent Per Day (null) (Email Sent Per Day) | |
Subject (string) or Subject (null) (Subject) | |
Body (string) or Body (null) (Body) |
{- "automation_name": "string",
- "schedule": {
- "Monday_maxCreators": 0,
- "Tuesday_maxCreators": 0,
- "Wednesday_maxCreators": 0,
- "Thursday_maxCreators": 0,
- "Friday_maxCreators": 0,
- "Saturday_maxCreators": 0,
- "Sunday_maxCreators": 0,
- "start_time": "string",
- "end_time": "string",
- "timezone": "string"
}, - "creators_to_include": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "filters": {
- "product_categories": [
- "string"
], - "follower_count": {
- "min": 0,
- "max": 0
}, - "creator_ethnicity": [
- "string"
], - "gender": [
- "string"
], - "age_range": [
- "string"
], - "languages": [
- "string"
], - "gmv": {
- "min": 0,
- "max": 0
}, - "units_sold": {
- "min": 0,
- "max": 0
}, - "average_views": {
- "min": 0,
- "max": 0
}, - "engagement_rate": {
- "min": 0,
- "max": 0
}, - "post_rate": {
- "min": 0,
- "max": 0
}, - "video_gpm": {
- "min": 0,
- "max": 0
}, - "live_gpm": {
- "min": 0,
- "max": 0
}, - "follower_age": [
- "string"
], - "follower_gender": [
- "string"
], - "face_visibility": [
- "string"
], - "content_style": [
- "string"
], - "production_quality": [
- "string"
], - "personality_tone": [
- "string"
], - "body_type": [
- "string"
], - "hair_type": [
- "string"
]
}, - "crm_group_id": "string",
- "crm_group_entered_after": "2019-08-24",
- "crm_group_entered_before": "2019-08-24"
}, - "creators_to_exclude": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "crm_groups": [
- "string"
], - "exclude_previously_messaged": false
}, - "messages": [
- {
- "type": "message",
- "body": "string",
- "image_url": "string",
- "product_id": "string",
- "submission_url_slug": "string"
}
], - "follow_ups": [
- {
- "delay_days": 30,
- "addons": [
- {
- "type": "message",
- "body": "string",
- "image_url": "string",
- "product_id": "string",
- "submission_url_slug": "string"
}
]
}
], - "target_collab": {
- "invitation_name": "string",
- "valid_until": "2019-08-24",
- "message": "string",
- "products": [
- {
- "product_id": "string",
- "commission_rate": 1,
- "shop_min_commission": 1,
- "shop_ads_commission_rate": 1
}
], - "content_type": "no_preference",
- "sample_policy": {
- "offer_free_samples": true,
- "auto_approve": true,
- "send_to": "brand_recipient"
}, - "support_contact": {
- "email": "string",
- "phone": "string"
}, - "lock_receivers_profiles": true
}, - "dm_config": {
- "spark_code": {
- "only_collect_creator_information": false,
- "spark_code_submission_url": "string"
}
}, - "sample_request": {
- "action": "approve",
- "rejection_reason": "NOT_MATCH",
- "approval_message": "string",
- "rejection_message": "string",
- "message_images": [
- "string"
], - "products": {
- "include_all_products": false,
- "selected_products": [
- {
- "product_id": "string",
- "max_approvals_per_week": 10000
}
], - "weekly_auto_approval_per_product": 1
}, - "minimum_performance_criteria": {
- "followers": 0,
- "avg_views": 0,
- "engagement_rate": 1,
- "post_rate": 1,
- "creator_gmv_30_days": 0,
- "gmv_per_sample": 0
}, - "maximum_performance_criteria": {
- "followers": 0,
- "avg_views": 0,
- "engagement_rate": 1,
- "post_rate": 1,
- "creator_gmv_30_days": 0,
- "gmv_per_sample": 0
}, - "auto_approval_settings": {
- "enabled": false,
- "total_weekly_approved_sample_limit": 1,
- "always_approve_status": "string",
- "always_approve_from_lists_ids": [
- 0
]
}, - "target_list": [
- 0
]
}, - "ai_enabled": true,
- "is_evergreen": true,
- "end_date": "2019-08-24",
- "business_hours_timezone": "string",
- "email_sent_per_day": 1,
- "subject": "string",
- "body": "string"
}{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Soft-delete (state=archived). Reversible only by Reacher support. Calling on already-archived returns 200 with already_archived: true.
| automation_id required | integer (Automation Id) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Per-creator outcomes for ONE automation: which creators got an invite/DM submitted, which were skipped (and why), which were previously invited, etc. This is the authoritative per-creator answer to 'what happened to each invite' — backed by the always-present target_collabs / Messages / skipped_creators tables, so it stays populated even after the aggregate creators_reached / skipped counters on the list/detail responses age out (those read from a stats view that only retains recently-active automations).
Queued ≠ delivered. An invite_submitted / outreach_sent outcome means Reacher's worker submitted the invite/DM through the same browser-automation path the portal uses. TikTok does not return a per-creator inbox-delivery receipt, so this is the most authoritative delivery signal available — not a confirmed inbox event. Requires a single shop.
| automation_id required | integer (Automation Id) |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 500 ] Default: 100 |
{- "data": [
- {
- "creator_handle": "string",
- "outcome": "string",
- "status": "string",
- "detail": "string",
- "skip_reason": "string",
- "invitation_id": "string"
}
], - "summary": {
- "total": 0,
- "invite_submitted": 0,
- "outreach_sent": 0,
- "previously_invited": 0,
- "invite_removed": 0,
- "skipped": 0,
- "unknown": 0
}, - "pagination": null
}The message copy configured on one automation, flattened into a uniform shape regardless of automation type: the TC invite template (tc_invite_message), the ordered DM sequence (message_sequence — array order is send order), follow-up steps, and AI-chatbot Q&A. Placeholders (e.g. {{creators username}}) are NOT substituted — this is the template. For the exact per-creator text that was actually sent, use GET /automations/{automation_id}/sent-messages. Requires a single shop.
| automation_id required | integer (Automation Id) |
{- "automation_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "tc_invite_message": "string",
- "message_sequence": [
- null
], - "follow_up_steps": [
- null
], - "ai_custom_qa": [
- null
], - "personalization": {
- "enabled": false,
- "tone": "string",
- "fallback_message": "string",
- "offer_discussion": "string",
- "product_description": "string",
- "product_selling_points": "string"
}
}What this automation actually sent, with honest coverage semantics:
dm_sent — the exact rendered DM text per creator (placeholders substituted at send time), grouped by creator, most recently messaged first. Filter with creator_handle; page depth with creator_limit / messages_per_creator.tc_sent — Target-Collab invitation batches (who was invited, when, status) plus the invite template. TikTok TC invites are sent from the template and the per-creator rendered text is not stored — exact_copy: false and coverage_note state this explicitly. When the automation is a campaign's TC automation, campaign carries the link.Hybrid automations (Message + TC) populate both sections. Empty sections carry an explicit message instead of blank lists. Read-only. Requires a single shop.
| automation_id required | integer (Automation Id) |
| creator_limit | integer (Creator Limit) [ 1 .. 100 ] Default: 20 |
| messages_per_creator | integer (Messages Per Creator) [ 1 .. 50 ] Default: 20 |
Creator Handle (string) or Creator Handle (null) (Creator Handle) |
{- "automation_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "template": {
- "automation_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "tc_invite_message": "string",
- "message_sequence": [
- null
], - "follow_up_steps": [
- null
], - "ai_custom_qa": [
- null
], - "personalization": {
- "enabled": false,
- "tone": "string",
- "fallback_message": "string",
- "offer_discussion": "string",
- "product_description": "string",
- "product_selling_points": "string"
}
}, - "dm_sent": {
- "exact_copy": true,
- "groups": [
- {
- "creator_name": "string",
- "creator_id": "string",
- "last_sent_at": "string",
- "messages": [
- {
- "content": "string",
- "sent_at": "string",
- "status": "string"
}
]
}
], - "creators_returned": 0,
- "total_creators": 0,
- "total_messages": 0,
- "message": "string"
}, - "tc_sent": {
- "exact_copy": false,
- "coverage_note": "string",
- "template_text": "string",
- "placeholders_present": false,
- "invitations": [
- {
- "sent_at": "string",
- "status": "string",
- "creator_count": 0,
- "creators": [
- "string"
], - "creators_truncated": false,
- "expiration_date": "string"
}
], - "invitations_returned": 0,
- "total_invitations": 0,
- "total_creators_invited": 0,
- "status_breakdown": {
- "property1": 0,
- "property2": 0
}, - "campaign": {
- "campaign_id": 0,
- "campaign_name": "string"
}, - "message": "string"
}, - "message": "string"
}Create a Target Collab (TC) invitation automation with optional follow-up DMs. Required: read_write scope, Idempotency-Key header. Pass X-Dry-Run: true to validate without persisting.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) | |
X-Created-Via (string) or X-Created-Via (null) (X-Created-Via) |
| automation_name required | string (Automation Name) [ 1 .. 120 ] characters |
required | object (AutomationSchedule) Per-day creator-outreach caps + run window. Stored into Automations.schedule JSONB. Same shape as the existing portal payload — keeps the portal and Public API agreeing on schema. |
object (CreatorsToInclude) Outreach-paradigm recipient inclusion. Three mutually-exclusive modes (cf. INTERNAL-design-review.md §11A):
The validator below rejects any request that mixes modes. The
| |
object (CreatorsToExclude) Outreach-paradigm recipient exclusion. Mirrors | |
required | object (TargetCollabConfig) TC-specific config — invitation metadata, commission rates, sample policy, content type, support contact. Maps to the legacy TC config blob shape (UPPERCASE root keys: BASE_INVITATION_NAME, VALID_UNTIL, TARGET_COLLAB_MESSAGE, EMAIL, PHONE_NUMBER, OFFER_FREE_SAMPLES, AUTO_APPROVE, PRODUCTS) — the worker reads from those, so the translator flattens this nested model accordingly. |
Array of objects (Messages) <= 5 items Initial-outreach addons — text, images, product cards, etc. ALL items in this list are sent immediately together when the automation engages a creator. Use | |
Array of objects (Follow Ups) <= 3 items Delayed follow-up steps. Each step has | |
| ai_enabled | boolean (Ai Enabled) Default: false |
End Date (string) or End Date (null) (End Date) | |
| auto_resolve_conflicts | string (Auto Resolve Conflicts) Default: "MOVE_NOT_ACCEPTED" Enum: "SKIP_ALL" "MOVE_NOT_ACCEPTED" "MOVE_ALL" How the runtime handles creators who already have a pending TC invite from another automation. SKIP_ALL leaves them untouched; MOVE_NOT_ACCEPTED (default — matches portal-created automations) re-targets creators whose prior invite was never accepted; MOVE_ALL re-targets regardless of prior invite state. Maps to |
| is_evergreen | boolean (Is Evergreen) Default: false When true, the automation continuously re-evaluates its |
Business Hours Timezone (string) or Business Hours Timezone (null) (Business Hours Timezone) When set, the runtime restricts outbound message delivery (initial outreach + follow-ups) to 9am–9pm in this IANA timezone (e.g. |
{- "automation_name": "string",
- "schedule": {
- "Monday_maxCreators": 0,
- "Tuesday_maxCreators": 0,
- "Wednesday_maxCreators": 0,
- "Thursday_maxCreators": 0,
- "Friday_maxCreators": 0,
- "Saturday_maxCreators": 0,
- "Sunday_maxCreators": 0,
- "start_time": "string",
- "end_time": "string",
- "timezone": "string"
}, - "creators_to_include": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "filters": {
- "product_categories": [
- "string"
], - "follower_count": {
- "min": 0,
- "max": 0
}, - "creator_ethnicity": [
- "string"
], - "gender": [
- "string"
], - "age_range": [
- "string"
], - "languages": [
- "string"
], - "gmv": {
- "min": 0,
- "max": 0
}, - "units_sold": {
- "min": 0,
- "max": 0
}, - "average_views": {
- "min": 0,
- "max": 0
}, - "engagement_rate": {
- "min": 0,
- "max": 0
}, - "post_rate": {
- "min": 0,
- "max": 0
}, - "video_gpm": {
- "min": 0,
- "max": 0
}, - "live_gpm": {
- "min": 0,
- "max": 0
}, - "follower_age": [
- "string"
], - "follower_gender": [
- "string"
], - "face_visibility": [
- "string"
], - "content_style": [
- "string"
], - "production_quality": [
- "string"
], - "personality_tone": [
- "string"
], - "body_type": [
- "string"
], - "hair_type": [
- "string"
]
}, - "crm_group_id": "string",
- "crm_group_entered_after": "2019-08-24",
- "crm_group_entered_before": "2019-08-24"
}, - "creators_to_exclude": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "crm_groups": [
- "string"
], - "exclude_previously_messaged": false
}, - "target_collab": {
- "invitation_name": "string",
- "valid_until": "2019-08-24",
- "message": "string",
- "products": [
- {
- "product_id": "string",
- "commission_rate": 1,
- "shop_min_commission": 1,
- "shop_ads_commission_rate": 1
}
], - "content_type": "no_preference",
- "sample_policy": {
- "offer_free_samples": false,
- "auto_approve": false,
- "send_to": "brand_recipient"
}, - "support_contact": {
- "email": "string",
- "phone": "string"
}
}, - "messages": [
- {
- "type": "message",
- "body": "string",
- "image_url": "string",
- "product_id": "string",
- "submission_url_slug": "string"
}
], - "follow_ups": [
- {
- "delay_days": 30,
- "addons": [
- {
- "type": "message",
- "body": "string",
- "image_url": "string",
- "product_id": "string",
- "submission_url_slug": "string"
}
]
}
], - "ai_enabled": false,
- "end_date": "2019-08-24",
- "auto_resolve_conflicts": "SKIP_ALL",
- "is_evergreen": false,
- "business_hours_timezone": "string"
}{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Create a TC Cleanup utility automation — re-targets creators in this shop who received a TC invite from a prior automation but didn't accept it. Conceptually closer to sample_request than to the proactive TC outreach types: products + creator selection only, no messages, no follow-ups. Required: read_write scope, Idempotency-Key header. Pass X-Dry-Run: true to validate without persisting.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) | |
X-Created-Via (string) or X-Created-Via (null) (X-Created-Via) |
| automation_name required | string (Automation Name) [ 1 .. 120 ] characters |
required | object (AutomationSchedule) Per-day creator-outreach caps + run window. Stored into Automations.schedule JSONB. Same shape as the existing portal payload — keeps the portal and Public API agreeing on schema. |
object (CreatorsToInclude) Outreach-paradigm recipient inclusion. Three mutually-exclusive modes (cf. INTERNAL-design-review.md §11A):
The validator below rejects any request that mixes modes. The
| |
object (CreatorsToExclude) Outreach-paradigm recipient exclusion. Mirrors | |
required | Array of objects (Products) [ 1 .. 50 ] items Products to re-invite the matching creators for. Cleanup uses the same TargetCollabProduct shape (product_id + commission rates) as a regular TC. Required — runtime needs at least one product to issue the re-invite. |
Invite Start Before Days (integer) or Invite Start Before Days (null) (Invite Start Before Days) Re-target only creators whose original TC invite was sent at least N days ago. Null = no lower bound on invite age. Persists as | |
Invite Expire After Days (integer) or Invite Expire After Days (null) (Invite Expire After Days) Re-target only creators whose original TC invite expires within the next N days. Null = no upper bound on time-to-expiry. Persists as | |
End Date (string) or End Date (null) (End Date) |
{- "automation_name": "string",
- "schedule": {
- "Monday_maxCreators": 0,
- "Tuesday_maxCreators": 0,
- "Wednesday_maxCreators": 0,
- "Thursday_maxCreators": 0,
- "Friday_maxCreators": 0,
- "Saturday_maxCreators": 0,
- "Sunday_maxCreators": 0,
- "start_time": "string",
- "end_time": "string",
- "timezone": "string"
}, - "creators_to_include": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "filters": {
- "product_categories": [
- "string"
], - "follower_count": {
- "min": 0,
- "max": 0
}, - "creator_ethnicity": [
- "string"
], - "gender": [
- "string"
], - "age_range": [
- "string"
], - "languages": [
- "string"
], - "gmv": {
- "min": 0,
- "max": 0
}, - "units_sold": {
- "min": 0,
- "max": 0
}, - "average_views": {
- "min": 0,
- "max": 0
}, - "engagement_rate": {
- "min": 0,
- "max": 0
}, - "post_rate": {
- "min": 0,
- "max": 0
}, - "video_gpm": {
- "min": 0,
- "max": 0
}, - "live_gpm": {
- "min": 0,
- "max": 0
}, - "follower_age": [
- "string"
], - "follower_gender": [
- "string"
], - "face_visibility": [
- "string"
], - "content_style": [
- "string"
], - "production_quality": [
- "string"
], - "personality_tone": [
- "string"
], - "body_type": [
- "string"
], - "hair_type": [
- "string"
]
}, - "crm_group_id": "string",
- "crm_group_entered_after": "2019-08-24",
- "crm_group_entered_before": "2019-08-24"
}, - "creators_to_exclude": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "crm_groups": [
- "string"
], - "exclude_previously_messaged": false
}, - "products": [
- {
- "product_id": "string",
- "commission_rate": 1,
- "shop_min_commission": 1,
- "shop_ads_commission_rate": 1
}
], - "invite_start_before_days": 1,
- "invite_expire_after_days": 1,
- "end_date": "2019-08-24"
}{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Create a Direct Message automation. The mode field selects between 4 variants: vanilla (text-only), with_image, with_product_card, spark_code (collect TikTok spark codes via form). Each mode has specific addon and config requirements — see model schema.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) | |
X-Created-Via (string) or X-Created-Via (null) (X-Created-Via) |
| automation_name required | string (Automation Name) [ 1 .. 120 ] characters |
| mode | string (Mode) Default: "vanilla" Enum: "vanilla" "with_image" "with_product_card" "spark_code" |
required | object (AutomationSchedule) Per-day creator-outreach caps + run window. Stored into Automations.schedule JSONB. Same shape as the existing portal payload — keeps the portal and Public API agreeing on schema. |
object (CreatorsToInclude) Outreach-paradigm recipient inclusion. Three mutually-exclusive modes (cf. INTERNAL-design-review.md §11A):
The validator below rejects any request that mixes modes. The
| |
object (CreatorsToExclude) Outreach-paradigm recipient exclusion. Mirrors | |
required | Array of objects (Messages) [ 1 .. 5 ] items Initial-outreach addons — text + optional image / product card / spark_code form. ALL items are sent immediately together when the automation engages a creator. Use |
Array of objects (Follow Ups) <= 3 items Delayed follow-up steps — same shape as TC. | |
DmConfig (object) or null | |
DmPersonalizationConfig (object) or null CORE-4857: enable AI personalization of the initial-outreach DM. Omit to send the message exactly as written. When set, the send engine rewrites the DM per creator from the [Block] tokens in your message text and falls back to | |
| ai_enabled | boolean (Ai Enabled) Default: false |
End Date (string) or End Date (null) (End Date) | |
| is_evergreen | boolean (Is Evergreen) Default: false When true, the automation continuously re-evaluates its |
Business Hours Timezone (string) or Business Hours Timezone (null) (Business Hours Timezone) When set, the runtime restricts outbound message delivery (initial outreach + follow-ups) to 9am–9pm in this IANA timezone (e.g. |
{- "automation_name": "string",
- "mode": "vanilla",
- "schedule": {
- "Monday_maxCreators": 0,
- "Tuesday_maxCreators": 0,
- "Wednesday_maxCreators": 0,
- "Thursday_maxCreators": 0,
- "Friday_maxCreators": 0,
- "Saturday_maxCreators": 0,
- "Sunday_maxCreators": 0,
- "start_time": "string",
- "end_time": "string",
- "timezone": "string"
}, - "creators_to_include": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "filters": {
- "product_categories": [
- "string"
], - "follower_count": {
- "min": 0,
- "max": 0
}, - "creator_ethnicity": [
- "string"
], - "gender": [
- "string"
], - "age_range": [
- "string"
], - "languages": [
- "string"
], - "gmv": {
- "min": 0,
- "max": 0
}, - "units_sold": {
- "min": 0,
- "max": 0
}, - "average_views": {
- "min": 0,
- "max": 0
}, - "engagement_rate": {
- "min": 0,
- "max": 0
}, - "post_rate": {
- "min": 0,
- "max": 0
}, - "video_gpm": {
- "min": 0,
- "max": 0
}, - "live_gpm": {
- "min": 0,
- "max": 0
}, - "follower_age": [
- "string"
], - "follower_gender": [
- "string"
], - "face_visibility": [
- "string"
], - "content_style": [
- "string"
], - "production_quality": [
- "string"
], - "personality_tone": [
- "string"
], - "body_type": [
- "string"
], - "hair_type": [
- "string"
]
}, - "crm_group_id": "string",
- "crm_group_entered_after": "2019-08-24",
- "crm_group_entered_before": "2019-08-24"
}, - "creators_to_exclude": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "crm_groups": [
- "string"
], - "exclude_previously_messaged": false
}, - "messages": [
- {
- "type": "message",
- "body": "string",
- "image_url": "string",
- "product_id": "string",
- "submission_url_slug": "string"
}
], - "follow_ups": [
- {
- "delay_days": 30,
- "addons": [
- {
- "type": "message",
- "body": "string",
- "image_url": "string",
- "product_id": "string",
- "submission_url_slug": "string"
}
]
}
], - "dm_config": {
- "spark_code": {
- "only_collect_creator_information": false,
- "spark_code_submission_url": "string"
}
}, - "personalization": {
- "enabled": true,
- "tone": "engaging",
- "fallback_message": "string",
- "offer_discussion": "",
- "product_description": "",
- "product_selling_points": ""
}, - "ai_enabled": false,
- "end_date": "2019-08-24",
- "is_evergreen": false,
- "business_hours_timezone": "string"
}{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Create an outbound email automation. Different recipient model from outreach — use selection_mode: mailing_list (with vault list IDs or upload emails inline) OR selection_mode: filters (creator search criteria). Constraint: each email_account_id can be linked to at most ONE active email automation.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) | |
X-Created-Via (string) or X-Created-Via (null) (X-Created-Via) |
| automation_name required | string (Automation Name) [ 1 .. 120 ] characters |
| email_account_id required | integer (Email Account Id) > 0 Pre-connected email account. Each account links to at most ONE active email automation per shop. |
| subject required | string (Subject) [ 1 .. 255 ] characters |
| body required | string (Body) [ 1 .. 50000 ] characters HTML or plaintext. |
| selection_mode required | string (Selection Mode) Enum: "mailing_list" "filters" |
EmailMailingList (object) or null | |
EmailFilters (object) or null | |
object (CreatorsToExclude) Outreach-paradigm recipient exclusion. Mirrors | |
Array of objects (Attachments) <= 10 items Email attachments — |
{- "automation_name": "string",
- "email_account_id": 0,
- "subject": "string",
- "body": "string",
- "selection_mode": "mailing_list",
- "mailing_list": {
- "list_upload_emails": [
- "string"
], - "lists_selected": [
- "string"
]
}, - "filters": {
- "min_creator_gmv": 0,
- "min_followers": 0,
- "min_engagement_rate": 1,
- "min_avg_views": 0,
- "regions": [
- "string"
], - "categories": [
- "string"
]
}, - "creators_to_exclude": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "crm_groups": [
- "string"
], - "exclude_previously_messaged": false
}, - "attachments": [
- {
- "name": "string",
- "url": "string"
}
]
}{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Auto-approve OR auto-reject incoming TikTok Shop sample requests by criteria. Side-effect: a CRM Group is internally created from the minimum_performance_criteria so creator membership stays dynamic. The new crm_group_id is returned in side_effects. If CRM-group creation fails, the automation still creates (logged + Sentry breadcrumb). Sample request type uses target_list (vault list IDs) instead of creators_to_include.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) | |
X-Created-Via (string) or X-Created-Via (null) (X-Created-Via) |
| automation_name required | string (Automation Name) [ 1 .. 120 ] characters |
required | object (SampleRequestPayload) Inner sample_request config — mirrors the legacy
|
AutomationSchedule (object) or null Optional — sample_request can run continuously. If set, the automation only auto-approves/rejects during scheduled hours. | |
object (CreatorsToExclude) Optional creator exclusion. Persists as |
{- "automation_name": "string",
- "sample_request": {
- "action": "approve",
- "rejection_reason": "NOT_MATCH",
- "approval_message": "string",
- "rejection_message": "string",
- "message_images": [
- "string"
], - "products": {
- "include_all_products": false,
- "selected_products": [
- {
- "product_id": "string",
- "max_approvals_per_week": 10000
}
], - "weekly_auto_approval_per_product": 1
}, - "minimum_performance_criteria": {
- "followers": 0,
- "avg_views": 0,
- "engagement_rate": 1,
- "post_rate": 1,
- "creator_gmv_30_days": 0,
- "gmv_per_sample": 0
}, - "maximum_performance_criteria": {
- "followers": 0,
- "avg_views": 0,
- "engagement_rate": 1,
- "post_rate": 1,
- "creator_gmv_30_days": 0,
- "gmv_per_sample": 0
}, - "auto_approval_settings": {
- "enabled": false,
- "total_weekly_approved_sample_limit": 1,
- "always_approve_status": "string",
- "always_approve_from_lists_ids": [
- 0
]
}, - "target_list": [
- 0
]
}, - "schedule": {
- "Monday_maxCreators": 0,
- "Tuesday_maxCreators": 0,
- "Wednesday_maxCreators": 0,
- "Thursday_maxCreators": 0,
- "Friday_maxCreators": 0,
- "Saturday_maxCreators": 0,
- "Sunday_maxCreators": 0,
- "start_time": "string",
- "end_time": "string",
- "timezone": "string"
}, - "creators_to_exclude": {
- "list_upload": [
- "string"
], - "lists_selected": [
- "string"
], - "crm_groups": [
- "string"
], - "exclude_previously_messaged": false
}
}{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Transition automation to running. Idempotent — already-running returns 200. Rejects with 422 AUTOMATION_NOT_STARTABLE when the automation can never run as configured (no schedule day with maxCreators > 0, or valid_until/end_date already passed) — this prevents the 'start succeeded but nothing ever sends' trap.
| automation_id required | integer (Automation Id) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}Transition automation to stopped. Idempotent.
| automation_id required | integer (Automation Id) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
{- "data": {
- "automation_id": 0,
- "shop_id": 0,
- "automation_name": "string",
- "automation_type": "string",
- "automation_status": "string",
- "state": "string",
- "config": { },
- "schedule": { },
- "creators_to_include": { },
- "creators_to_exclude": { },
- "crm_group_id": "string",
- "ai_enabled": false,
- "end_date": "string",
- "created_at": "string",
- "updated_at": "string",
- "created_via": "string",
- "side_effects": { }
}, - "dry_run": false,
- "side_effects": { }
}AI-personalized outreach (CORE-4857): preview the message a creator would receive, resolve product blocks, retone copy, and read fallback stats + per-creator sent history. Configure it on a DM via the personalization block of POST /automations/dm. Single-shop only.
Generate the AI personalization blocks for one creator and return the fully assembled message — exactly what a send with the same configuration would ship. When the creator has too little signal to personalize, the brand fallback_message is returned instead (is_fallback: true).
Content Discussion and Product Discussion are AI-generated from the creator's own signals; Product Description / Selling Points / Offer are the fixed strings you pass in (resolve product blocks first via POST /personalization/product-blocks). Region and brand name are taken from the shop (brand name defaults to the shop name).
API previews are stateless: nothing is stored, and a later send generates its own copy (or reuses a lock approved in the Reacher portal composer). Generation endpoints share a separate quota (20/min, 500/hr per key). Requires a single shop.
required | object (PersonalizationPreviewCreator) The single creator to generate a preview for. |
| message_body required | string (Message Body) [ 1 .. 4000 ] characters The DM template with [Block] tokens (mirrors the automation's CREATOR_MESSAGE). |
| tone | string (Tone) Default: "engaging" Enum: "engaging" "bold" "inspirational" |
| fallback_message required | string (Fallback Message) [ 1 .. 4000 ] characters Sent (name/product blocks filled) when the creator has too little signal to personalize. Required — matches the DM config contract: personalization must always have a safe fallback, so a low-signal preview never returns an empty message. |
| brand_name | string (Brand Name) <= 200 characters Default: "" Brand display name used in the copy. Defaults to the shop name when omitted. |
| product_description | string (Product Description) <= 4000 characters Default: "" Pre-resolved [Product Description]. Get it from POST /personalization/product-blocks. |
| product_selling_points | string (Product Selling Points) <= 2000 characters Default: "" Pre-resolved [Product Selling Points]. Get it from POST /personalization/product-blocks. |
| offer_discussion | string (Offer Discussion) <= 2000 characters Default: "" [Offer Discussion] block value — the brand's offer text. |
{- "creator": {
- "creator_id": "string",
- "creator_handle": "string",
- "creator_first_name": ""
}, - "message_body": "string",
- "tone": "engaging",
- "fallback_message": "string",
- "brand_name": "",
- "product_description": "",
- "product_selling_points": "",
- "offer_discussion": ""
}{- "creator_id": "string",
- "message": "string",
- "is_fallback": true,
- "blocks_used": [
- "string"
]
}Resolve the two product-sourced personalization blocks for one of your products: [Product Description] (the product's own catalog text) and [Product Selling Points] (2–3 concrete selling points DERIVED from the product's real title/description/attributes — never invented). Use the returned strings verbatim in POST /personalization/preview and in the personalization block of POST /automations/dm, so preview and send share the same fixed copy.
Both blocks degrade to empty strings (the block simply drops out of the message) ONLY when the product isn't in this shop's catalog or has too little grounded content; a failed lookup (transient database error) returns 500 instead, so empty strings are always a true statement about the product, never an outage artifact — safe to store. Requires a single shop.
| product_id required | string (Product Id) [ 1 .. 100 ] characters A product id in this shop's catalog. Blocks resolve empty if it isn't. |
{- "product_id": "string"
}{- "product_description": "",
- "product_selling_points": ""
}Rewrite the shared message body in a new tone (engaging | bold | inspirational), preserving every [Block] token so the template stays intact. This is brand-level copy (one message for everyone) — there's no creator here. Degrades to the original body on any failure, so the caller never ends up with a broken template. Requires a single shop.
| message_body required | string (Message Body) [ 1 .. 4000 ] characters The message body to rewrite. Every [Block] token is preserved. |
| tone | string (Tone) Default: "engaging" Enum: "engaging" "bold" "inspirational" |
{- "message_body": "string",
- "tone": "engaging"
}{- "message": "string"
}How many of an automation's personalized outreach messages used the brand fallback (creator had too little signal to personalize) versus were fully personalized. A lifetime aggregate across every send run of the automation, plus the fallback_rate convenience ratio. Counts are recorded when the send engine locks the copy for delivery (immediately before the DM goes out), so a delivery that fails at the last step may still be counted. An automation with no personalized sends yet returns zeros; an automation not in this shop returns 404. Requires a single shop.
| automation_id required | integer (Automation Id) |
{- "automation_id": 0,
- "messages_sent": 0,
- "fallback_used": 0,
- "fallback_rate": 0
}The personalized outreach messages this shop sent to one creator (the creator record's audit trail), newest first — the exact copy, whether it was fully personalized or fell back. Rows are recorded when the send engine locks the copy for delivery, so sent_at marks the delivery attempt, not a provider receipt. creator_id is the TikTok creator id (as returned by GET /automations/{id}/creators or GET /automations/{id}/sent-messages). Returns an empty list when this creator has never been personalized in this shop. Requires a single shop.
| creator_id required | string (Creator Id) |
| limit | integer (Limit) [ 1 .. 100 ] Default: 20 |
{- "creator_id": "string",
- "count": 0,
- "messages": [
- {
- "automation_id": 0,
- "message": "string",
- "is_fallback": true,
- "tone": "string",
- "sent_at": "string"
}
]
}Send a single TikTok Shop Target Collab invitation to one creator by handle — convenience surface over the two-step automation create + start. For >10 invites at a time, use POST /automations/target-collab with a multi-creator audience instead. Also exposes GET/PUT /target-collabs/support-contact-default to configure a shop-level default support_contact, which the TC create surfaces fall back to when a request omits it.
Send a single TikTok Shop Target Collab (TC) invitation to a creator by handle. This is a convenience surface — it internally creates a single-creator TC automation and immediately starts it.
Queued semantics. The response returns immediately with status: "queued". Actual TC delivery happens asynchronously through Reacher's TC delivery worker (browser automation, the same path the portal uses). Typical end-to-end latency is a few seconds, sometimes longer under worker load. Poll GET /public/v1/automations/{automation_id} for delivery status and target_collabs.invitation_id once the worker submits.
Not for bulk. For >10 invites at a time, use POST /public/v1/automations/target-collab directly with a multi-creator audience — that's more efficient than calling this endpoint in a loop, and exposes the full TC feature set (content type, sample policy, follow-up DMs).
Required. read_write scope, Idempotency-Key header. Pass X-Dry-Run: true to validate without persisting or queueing.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| creator_handle required | string (Creator Handle) [ 1 .. 64 ] characters TikTok @-handle (without the |
| product_id required | string (Product Id) [ 1 .. 64 ] characters TikTok Shop product ID to attach to the invitation. |
| commission_rate required | number (Commission Rate) [ 0 .. 1 ] Affiliate commission rate (0.0-1.0, e.g. 0.20 for 20%). |
Shop Ads Commission Rate (number) or Shop Ads Commission Rate (null) (Shop Ads Commission Rate) Optional Shop Ads (co-funded) commission rate (0.0-1.0). When set, persists into the legacy PRODUCTS blob at the per-product level; the TC runtime fills the matching field on the TC form. Omit to leave unset (worker treats as not configured). | |
| message required | string (Message) [ 1 .. 500 ] characters TC card message body shown to the creator (max 500 chars). Mirrors |
| invitation_name required | string (Invitation Name) [ 1 .. 30 ] characters Name shown on the TC invitation card (max 30 chars). Same field as |
Valid Until (string) or Valid Until (null) (Valid Until) Date the TC card stops being valid. Defaults to today + 30 days when omitted. After this date the dispatcher stops the underlying automation (see | |
TargetCollabDirectSupportContact (object) or null Brand-side support contact shown on the TC card. Optional ONLY when this shop has a default configured via |
{- "creator_handle": "string",
- "product_id": "string",
- "commission_rate": 1,
- "shop_ads_commission_rate": 1,
- "message": "string",
- "invitation_name": "string",
- "valid_until": "2019-08-24",
- "support_contact": {
- "email": "string",
- "phone": "string"
}
}{- "automation_id": 0,
- "status": "string",
- "creator_id": "string",
- "creator_handle": "string",
- "shop_id": 0,
- "check_status_at": "string",
- "queued_at": "string",
- "dry_run": false
}Read the shop-level default support_contact used as a fallback when a TC create request omits support_contact (CORE-5428).
Returns configured: false (with null fields) when no default is set — in that state TC creates still require a per-request support_contact. Requires a single shop (x-shop-id).
{- "shop_id": 0,
- "configured": true,
- "email": "string",
- "phone": "string",
- "updated_at": "string"
}Configure the shop-level default support_contact once, so TC create requests can omit it (CORE-5428). A per-request support_contact still overrides this default for that request.
email is required; phone is optional. The upsert is keyed on the shop, so re-sending the same body yields the same state. Requires read_write scope, a single shop (x-shop-id), and an Idempotency-Key header (for contract consistency with the other public-API write endpoints) — replay/conflict semantics match those writes.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) |
| email required | string (Email) [ 3 .. 255 ] characters Default contact email shown to the creator on the TC card. |
Phone (string) or Phone (null) (Phone) Optional default contact phone. E.164 format recommended. |
{- "email": "string",
- "phone": "string"
}{- "shop_id": 0,
- "configured": true,
- "email": "string",
- "phone": "string",
- "updated_at": "string"
}Fetch time-series data for one or more metrics over a date range. Returns daily/weekly/monthly data points for charting trends. Available metrics: gmv (affiliate-attributed), total_gmv (full shop from the Seller Center scrape), creators, videos_posted, video_views, gmv_per_video, gmv_per_sample, creators_reached, creators_messaged, tc_invites_sent, samples_approved, sample_requests, gmv_driving_videos, new_creators_posting, open_collabs, accepted_tc_count, emails_sent, dm_responses, reply_rate. Seller Center whole-shop cards: orders, units_sold, aov, ctr, conversion_rate (aov/ctr/conversion_rate are ratios computed over the full window, not averages of daily ratios; 0 for shops not yet on the Seller Center sync). Granularity (day/week/month) is auto-detected based on the date range if not specified. IMPORTANT: 'creators' returns distinct creators PER DAY — summing daily values double-counts creators active on multiple days. For the headline distinct count over the full period, use POST /metrics/summary instead. Similarly, gmv_per_video and gmv_per_sample are daily ratios — use /metrics/summary for the period-level headline values. Dates default to the newest day with settled data for the shop (typically yesterday; up to 2 days back while a day finalizes).
| metrics required | Array of strings (Metrics) [ 1 .. 24 ] items Items Enum: "gmv" "total_gmv" "creators" "videos_posted" "video_views" "gmv_per_video" "gmv_per_sample" "creators_reached" "creators_messaged" "tc_invites_sent" "samples_approved" "sample_requests" "gmv_driving_videos" "new_creators_posting" "open_collabs" "accepted_tc_count" "emails_sent" "dm_responses" "reply_rate" "orders" "units_sold" "aov" "ctr" "conversion_rate" |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Granularity (string) or Granularity (null) (Granularity) |
{- "metrics": [
- "gmv"
], - "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "granularity": "day"
}{- "data": {
- "property1": [
- {
- "date": "string",
- "value": 0
}
], - "property2": [
- {
- "date": "string",
- "value": 0
}
]
}, - "granularity": "string",
- "start_date": "string",
- "end_date": "string",
- "currency": "string",
- "shops_queried": [
- "string"
]
}Pre-computed headline scalar metrics for a date range, matching the Reacher dashboard's top-level KPIs exactly. Use this for summary cards and headline numbers. Includes derived metrics like active_creators (distinct count, not daily sum), gmv_per_video, and gmv_per_sample. Also includes Seller Center whole-shop cards: orders, units_sold, aov, ctr, conversion_rate (all-channel; aov/ctr/conversion_rate are ratios computed over the full window). Defaults to the last 30 days if no dates are specified. Dates default to the newest day with settled data for the shop (typically yesterday; up to 2 days back while a day finalizes).
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) |
{- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "gmv": 0,
- "total_gmv": 0,
- "active_creators": 0,
- "video_views": 0,
- "videos_posted": 0,
- "samples_approved": 0,
- "gmv_per_video": 0,
- "gmv_per_sample": 0,
- "sample_requests": 0,
- "gmv_driving_videos": 0,
- "new_creators_posting": 0,
- "open_collabs": 0,
- "accepted_tc_count": 0,
- "creators_reached": 0,
- "creators_messaged": 0,
- "tc_invites_sent": 0,
- "emails_sent": 0,
- "dm_responses": 0,
- "reply_rate": 0,
- "orders": 0,
- "units_sold": 0,
- "aov": 0,
- "ctr": 0,
- "conversion_rate": 0,
- "errors": [
- "string"
], - "start_date": "string",
- "end_date": "string",
- "currency": "string",
- "shops_queried": [
- "string"
]
}Full TikTok Seller Center shop GMV (ads + organic + affiliate) — daily series and window totals with channel breakdown. Distinct from POST /metrics/timeseries metric=gmv, which is affiliate-attributed only.
Daily GMV for one shop from the TikTok Seller Center daily rollup, including channel breakdown (video → affiliate/seller, live → affiliate/seller, product_card → shop_tab/search) and traffic (product impressions/clicks).
Differs from POST /metrics/timeseries metric=gmv — that endpoint reports affiliate-attributed GMV only (Reacher's view of creator-driven sales). This endpoint reports the total shop GMV including ads / Smart+ and organic. Use this when the customer wants numbers matching their TikTok Seller Center dashboard.
Single-shop only — set x-shop-id to a specific shop ID. Defaults to last 30 days ending yesterday. Max range 90 days (TikTok backfill depth). The newest available day is yesterday; today's row is not returned. Empty series is a normal 200 response — Seller Center coverage is still rolling out.
Start Date (string) or Start Date (null) (Start Date) Inclusive window start (YYYY-MM-DD). Defaults to 29 days before | |
End Date (string) or End Date (null) (End Date) Inclusive window end (YYYY-MM-DD). Defaults to yesterday (today is excluded because the daily row is still incomplete). |
{- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "shop_id": 0,
- "currency_code": "string",
- "granularity": "daily",
- "start_date": "string",
- "end_date": "string",
- "series": [
- {
- "date": "string",
- "gmv": 0,
- "orders": 0,
- "items_sold": 0,
- "customers": 0,
- "aov": 0,
- "channels": {
- "video": {
- "gmv": 0,
- "affiliate": 0,
- "seller": 0
}, - "live": {
- "gmv": 0,
- "affiliate": 0,
- "seller": 0
}, - "product_card": {
- "gmv": 0,
- "shop_tab": 0,
- "search": 0
}
}, - "traffic": {
- "product_impressions": 0,
- "product_clicks": 0
}
}
]
}Window totals for one shop from the TikTok Seller Center daily rollup — SUMmed across the window with the same channel hierarchy as the timeseries response.
Same coverage caveats as the timeseries endpoint. aov is recomputed as total GMV / total orders over the window (a window-correct value, not the average of daily AOVs). customers is the SUM of daily unique-customer counts — buyers who purchased on multiple days are double-counted; a true window-distinct count is not derivable from this rollup.
Start Date (string) or Start Date (null) (Start Date) Inclusive window start (YYYY-MM-DD). Defaults to 29 days before | |
End Date (string) or End Date (null) (End Date) Inclusive window end (YYYY-MM-DD). Defaults to yesterday. |
{- "start_date": "2019-08-24",
- "end_date": "2019-08-24"
}{- "shop_id": 0,
- "currency_code": "string",
- "start_date": "string",
- "end_date": "string",
- "day_count": 0,
- "gmv": 0,
- "orders": 0,
- "items_sold": 0,
- "customers": 0,
- "aov": 0,
- "channels": {
- "video": {
- "gmv": 0,
- "affiliate": 0,
- "seller": 0
}, - "live": {
- "gmv": 0,
- "affiliate": 0,
- "seller": 0
}, - "product_card": {
- "gmv": 0,
- "shop_tab": 0,
- "search": 0
}
}, - "traffic": {
- "product_impressions": 0,
- "product_clicks": 0
}
}Affiliate funnel stage counts matching the dashboard's 'Affiliate Funnel' section. Shows creators at each stage: sample requested, approved, content posted, content unfulfilled, GMV generated, and top creators (>$10k GMV). Data is based on the last 90 days.
nullList all GMV Max (TikTok Smart+) campaigns for the shop(s) addressed by x-shop-id. Returns cached campaign metadata last synced from TikTok by the portal — call the portal's sync endpoints to refresh. Supports multi-shop (x-shop-id: all or comma-separated).
{- "data": [
- {
- "shop_id": 0,
- "campaign_id": "string",
- "campaign_name": "string",
- "status": "string",
- "shopping_ads_type": "string",
- "budget": 0,
- "roas_bid": 0,
- "last_synced_at": "string",
- "currency": "string"
}
], - "shops_queried": [
- "string"
]
}Daily performance metrics (spend, impressions, clicks, orders, gross_revenue, ROAS, CPC, CPM, CTR) for one campaign over a date range. Date range may not exceed 90 days (inclusive). Defaults to the last 30 days. Multi-shop is supported — when multiple shops are addressed via x-shop-id (a comma-separated list or all), the campaign's owning shop is resolved automatically and metrics are returned for that shop.
| campaign_id required | string (Campaign Id) [ 1 .. 64 ] characters |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) |
{- "campaign_id": "string",
- "shop_id": 0,
- "data": [
- {
- "date": "string",
- "spend": 0,
- "impressions": 0,
- "clicks": 0,
- "orders": 0,
- "gross_revenue": 0,
- "cpc": 0,
- "cpm": 0,
- "ctr": 0,
- "roas": 0
}
], - "start_date": "string",
- "end_date": "string",
- "currency": "string"
}Aggregated GMV Max KPIs for a shop over a recent window, with previous-period comparison: spend, revenue, orders, impressions, clicks, ROAS — plus a per-day breakdown for charting. Single shop only (set x-shop-id to a specific shop ID). Mirrors the portal Dashboard exactly.
| days | integer (Days) [ 1 .. 90 ] Default: 7 Window size in days (default 7). |
nullDetail for one campaign: name, status, ad type, budget, ROAS bid, last sync time, plus the campaign's daily metric rows (spend, impressions, clicks, orders, gross_revenue, CPC, CPM, CTR, ROAS). Single shop only — the caller must address the campaign's owning shop via x-shop-id. For multi-shop callers, use the /campaigns list endpoint to discover which shop owns a campaign before requesting its detail.
| campaign_id required | string (Campaign Id) [ 1 .. 64 ] characters |
nullList the synced creatives (videos, spark codes, etc.) attached to a specific GMV Max campaign, with per-creative performance summaries. Single shop only.
| campaign_id required | string (Campaign Id) [ 1 .. 64 ] characters GMV Max campaign ID. |
nullCached spark-code sync state for the shop: which codes are queued, in flight, succeeded, or failed against TikTok. Read-only — sync itself is JWT-only on the portal. Single shop only.
nullHard-coded set of quick-start automation templates the portal exposes (e.g. 'Boost top performers', 'Wind down low-ROAS'). Useful as a starting point when scaffolding an automation via the Phase-2 writes API. Not shop-scoped — same set for every caller.
nullList all GMV Max automations configured for the shop, with their current status, trigger frequency, boost window, and last-run summary. Single shop only — automations are per-shop.
nullCreate a new automation that watches the selected campaign(s) and fires creative boosts when its conditions match. Requires read_write scope. Idempotent via the Idempotency-Key header — replays of the same key + same body return the cached 201 instead of creating a duplicate row.
X-Dry-Run: true validates the body and echoes the would-be row without touching the DB. Single shop only — set x-shop-id to the owning shop.
Every set_up_creative_boost action requires a total_creative_boost_cost guardrail (lifetime spend cap) — missing one returns 422 TOTAL_BUDGET_CAP_REQUIRED. Each campaign_id can only belong to one active automation at a time — conflicts return 422 CAMPAIGN_ALREADY_ASSIGNED.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| name required | string (Name) [ 1 .. 255 ] characters |
Template Type (string) or Template Type (null) (Template Type) Optional reference to one of the | |
| trigger_frequency | string (TriggerFrequency) Default: "daily" Value: "daily" How often the automation evaluates. Only |
| campaign_ids | Array of strings (Campaign Ids) TikTok GMV Max campaign IDs the automation acts on. Each campaign_id can only be assigned to one active automation at a time — the controller rejects conflicts with a 422. |
Array of objects (Conditions) | |
Array of objects (Actions) | |
Array of objects (Guardrails) | |
Boost Start Date (string) or Boost Start Date (null) (Boost Start Date) First day boosts may fire. Must be paired with | |
Boost End Date (string) or Boost End Date (null) (Boost End Date) |
{- "name": "string",
- "template_type": "string",
- "trigger_frequency": "daily",
- "campaign_ids": [
- "string"
], - "conditions": [
- {
- "metric": "creative_roi",
- "operator": "lt",
- "value": 0,
- "lookback_days": 3
}
], - "actions": [
- {
- "action_type": "set_up_creative_boost",
- "params": { }
}
], - "guardrails": [
- {
- "rule_type": "total_creative_boost_cost",
- "operator": "lt",
- "value": 0
}
], - "boost_start_date": "2019-08-24",
- "boost_end_date": "2019-08-24"
}nullDetail for one automation: full configuration (conditions, actions, guardrails) plus its 10 most recent runs. Single shop only — automation_ids are scoped per shop.
| automation_id required | integer (Automation Id) >= 1 |
nullPatch an existing automation. Only active, non-expired automations are editable — stopped, deleted, or past-end-date rows return 422 with AUTOMATION_NOT_EDITABLE or AUTOMATION_EXPIRED.
PATCH semantics — fields the caller does NOT include are left unchanged. Sending null for boost_start_date / boost_end_date clears the boost window (both dates must be sent together).
X-Dry-Run: true echoes the patch without writing. Idempotent via the Idempotency-Key header. Single shop only.
| automation_id required | integer (Automation Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
Name (string) or Name (null) (Name) | |
TriggerFrequency (string) or null | |
Array of Campaign Ids (strings) or Campaign Ids (null) (Campaign Ids) | |
Array of Conditions (objects) or Conditions (null) (Conditions) | |
Array of Actions (objects) or Actions (null) (Actions) | |
Array of Guardrails (objects) or Guardrails (null) (Guardrails) | |
Boost Start Date (string) or Boost Start Date (null) (Boost Start Date) | |
Boost End Date (string) or Boost End Date (null) (Boost End Date) |
{- "name": "string",
- "trigger_frequency": "daily",
- "campaign_ids": [
- "string"
], - "conditions": [
- {
- "metric": "creative_roi",
- "operator": "lt",
- "value": 0,
- "lookback_days": 3
}
], - "actions": [
- {
- "action_type": "set_up_creative_boost",
- "params": { }
}
], - "guardrails": [
- {
- "rule_type": "total_creative_boost_cost",
- "operator": "lt",
- "value": 0
}
], - "boost_start_date": "2019-08-24",
- "boost_end_date": "2019-08-24"
}nullSoft-delete an automation (status='deleted'). The row remains in the DB but is excluded from list / detail views. Re-deleting an already-deleted automation is a no-op that still returns 200 (idempotent on the row itself).
Pending boost rows queued by this automation are cancelled in the background — best-effort, not awaited here. Single shop only.
| automation_id required | integer (Automation Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
nullFull run history for one automation (most recent first), including trigger source, start/finish timestamps, success/failure status, and per-run summary metrics. Single shop only.
| automation_id required | integer (Automation Id) >= 1 |
nullPaginated per-event activity log for one automation (campaign boost / cancel events the automation produced), plus an aggregate summary across the full history. Supports the same status and search filters the portal does. Single shop only.
| automation_id required | integer (Automation Id) >= 1 |
Status (string) or Status (null) (Status) Filter by activity status (matches portal). | |
Search (string) or Search (null) (Search) Free-text search across activity rows. | |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 20 |
nullMark an automation status='stopped' (terminal — no resume). Already-stopped automations are returned unchanged (idempotent on the row itself, independent of the Idempotency-Key header).
Boost cancellation against TikTok is best-effort and runs in a background thread on the portal side; this endpoint does not wait for it. Single shop only.
| automation_id required | integer (Automation Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
nullSynchronously authorise the listed spark codes against the shop's TikTok Business ad account. Each code fires one TikTok /tt_video/authorize/ call:
sync_status flips to synced.pending so the offline CRJ retries it; the response counts this in queued.failed with the error string.Up to 100 codes per request. Shops without an active TikTok Business connection return 422 TIKTOK_NOT_CONNECTED. Single shop only.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| spark_codes required | Array of strings (Spark Codes) [ 1 .. 100 ] items Up to 100 spark codes to sync in one request. Each code fires one TikTok |
{- "spark_codes": [
- "string"
]
}nullQueue every spark code for the shop that isn't already synced. Writes pending rows to gmv_max_spark_code_sync; the offline CRJ fires the TikTok /tt_video/authorize/ calls on its next run.
Returns immediately with {queued, skipped, message}. Shops without an active TikTok Business connection return 422 TIKTOK_NOT_CONNECTED. Single shop only.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
POST /public/v1/gmv-max/spark-codes/sync-all — queue every
unsynced code for the shop. Returns immediately with a queue count;
the offline CRJ actually fires the TikTok calls.
Has no body fields (shop_id comes from x-shop-id); kept as a model
so we can still extra="forbid" against accidental payloads.
{ }nullNatural-language creator search backed by the same retrieval pipeline as the portal. Search and CSV export are both available, with a 50,000-row hard cap per export.
Search the global TikTok creator universe with a natural-language query. Returns paginated creator results scored against the query, with optional browse mode when query is omitted (returns top creators in the shop's region). Requires a single x-shop-id — the shop's region determines which regional creator table is searched.
Query (string) or Query (null) (Query) Natural-language search query. Whitespace-only is treated as no query (browse mode). | |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 20 |
{- "query": "string",
- "page": 1,
- "page_size": 20
}{- "data": [
- {
- "creator_name": "string",
- "categories": [
- "string"
], - "follower_count": 0,
- "gmv": 0,
- "post_rate": 0,
- "engagement_rate": 0,
- "bio": "string",
- "top_videos": [
- {
- "video_id": "string",
- "tiktok_url": "string",
- "views": 0
}
]
}
], - "pagination": {
- "total": 0,
- "page": 0,
- "page_size": 0
}
}Export up to 50,000 matching creators as CSV. The response is a streaming attachment; the X-Creator-Row-Count response header reports the actual row count. CSV only — XLSX is not supported on the public API. Requires a single x-shop-id.
Query (string) or Query (null) (Query) Natural-language search query. Omit (or pass whitespace-only) to export the full browse universe for your shop's region. | |
Array of Creator Ids (strings) or Creator Ids (null) (Creator Ids) Explicit list of creator IDs to export. Mutually exclusive with query. |
{- "query": "string",
- "creator_ids": [
- "string"
]
}{- "detail": [
- {
- "loc": [
- "string"
], - "msg": "string",
- "type": "string"
}
]
}Read the shop's creator DM inbox and reply to creators programmatically (e.g. from an AI agent). Replies require the read_write scope and only work in conversations a creator has already opened.
The shop's creator DM inbox. Use unreplied_only=true to get conversations awaiting a reply (what an AI agent typically iterates).
| offset | integer (Offset) >= 0 Default: 0 |
| limit | integer (Limit) [ 1 .. 200 ] Default: 50 |
| unread_only | boolean (Unread Only) Default: false |
| unreplied_only | boolean (Unreplied Only) Default: false |
{- "data": [
- {
- "creator_handle": "string",
- "last_message_text": "string",
- "last_message_time": "string",
- "last_message_sender": "string",
- "unread_count": 0
}
], - "offset": 0,
- "limit": 0,
- "has_more": true,
- "total_count": 0
}| creator_handle required | string (Creator Handle) |
| page | integer (Page) >= 1 Default: 1 |
{- "creator_handle": "string",
- "data": [
- {
- "id": 0,
- "sender": "string",
- "content_type": "string",
- "text": "string",
- "sent_at": "string",
- "image": {
- "url": "string",
- "width": 0,
- "height": 0
}, - "product_card": {
- "product_id": "string",
- "product_name": "string",
- "image_url": "string"
}, - "target_collaboration_card": {
- "invitation_group_id": "string"
}, - "free_sample_card": {
- "apply_id": "string"
}, - "crm_text_with_image_card": {
- "title": "string",
- "content": "string",
- "url": "string"
}, - "crm_text_with_products_card": {
- "title": "string",
- "content": "string",
- "products": [
- {
- "product_id": "string",
- "product_name": "string",
- "image_url": "string"
}
]
}
}
], - "page": 0,
- "has_more": true
}Sends a plain-text DM to the creator in an EXISTING conversation (the creator must have an open thread with the shop — TikTok does not allow cold-opening a DM). Idempotency-Key required. X-Dry-Run: true validates and echoes without contacting TikTok.
| creator_handle required | string (Creator Handle) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| message required | string (Message) [ 1 .. 4000 ] characters Plain-text reply body to send to the creator. |
{- "message": "string"
}{- "dry_run": true,
- "would_send_to": "string",
- "message": "string"
}Send a TikTok IMAGE message. Provide an HTTPS image_url; we fetch it server-side, upload to TikTok, and dispatch into the existing conversation. Same auth/scope/idempotency/rate-limit/X-Dry-Run semantics as the text reply. v1: no caption (send a text reply separately if you also want copy).
| creator_handle required | string (Creator Handle) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| image_url required | string (Image Url) [ 10 .. 2000 ] characters HTTPS URL of an image to forward to the creator. We fetch it server-side (must resolve to a public IP, return Content-Type image/*, ≤ 5 MB), then upload to TikTok and dispatch. |
{- "image_url": "stringstri"
}{- "dry_run": true,
- "would_send_to": "string",
- "image_url": "string"
}Send a TikTok PRODUCT_CARD message linking one of THIS shop's products. We verify the product_id belongs to the shop's catalog. Same auth/scope/idempotency/rate-limit/X-Dry-Run semantics as the text reply. No caption (send a text reply separately for copy).
| creator_handle required | string (Creator Handle) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| product_id required | string (Product Id) [ 1 .. 64 ] characters A TikTok product_id from THIS shop's catalog. Sending another shop's product_id is rejected with 400. |
{- "product_id": "string"
}{- "dry_run": true,
- "would_send_to": "string",
- "product_id": "string"
}Persist a reply on the conversation WITHOUT delivering it to the creator. The draft surfaces in the Reacher inbox for a human to review and either send via the existing /reply* endpoints or discard via DELETE /drafts/{id}. Idempotency-Key required. X-Dry-Run: true validates and echoes without persisting.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| creator_handle required | string (Creator Handle) [ 1 .. 255 ] characters The creator's TikTok handle (with or without leading @). Must already have an open conversation with this shop — drafts can only be staged on existing conversations, the same prerequisite TikTok enforces on the live-send path. |
Text (string) or Text (null) (Text) Plain-text reply body. Set this OR | |
Image Url (string) or Image Url (null) (Image Url) HTTPS URL of an image to send. Same SSRF + size + type constraints as the live /reply/image endpoint will apply when the human ships the draft — we do NOT fetch the URL at draft time (no outbound network call from this endpoint). Set this OR | |
Product Id (string) or Product Id (null) (Product Id) A TikTok product_id from THIS shop's catalog. Ownership is verified ONLY when the human clicks Send in the inbox — the draft endpoint does not pre-check the catalog (the catalog can change between draft and send anyway). Set this OR |
{- "creator_handle": "string",
- "text": "string",
- "image_url": "stringstri",
- "product_id": "string"
}{- "dry_run": true,
- "would_create_for_handle": "string",
- "content_type": "string",
- "text": "string",
- "image_url": "string",
- "product_id": "string"
}Drafts for the given creator on this shop, newest first. Drafts only — does NOT return sent messages (see GET /conversations/{handle}/messages for those).
| creator_handle required | string (Creator Handle) |
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 25 |
{- "data": [
- {
- "id": 0,
- "conversation_id": 0,
- "content_type": "string",
- "text_content": "string",
- "payload": { },
- "created_at": "string",
- "expires_at": "string",
- "created_by_api_key_id": 0
}
], - "page": 0,
- "page_size": 0,
- "total": 0,
- "has_more": true
}Remove a draft by id. 404 if the id is unknown, 403 if the draft belongs to a different shop than the caller's x-shop-id. Idempotency-Key is NOT required for delete (delete is naturally idempotent — a second DELETE just returns 404).
| draft_id required | integer (Draft Id) |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
{- "detail": [
- {
- "loc": [
- "string"
], - "msg": "string",
- "type": "string"
}
]
}Create and manage Creator Community Campaigns — Retainer, Challenge, Leaderboard, and Live GMV Challenge types. Full surface: CRUD, creator accept/reject/reactivate/remove, cross-shop add-to-campaign (move) with region + same-customer guards, content tracking, request-more-content, deposit-intent + settlement with full idempotency + dry-run + audit logging on the money-moving path.
Paginated list of the shop's creator campaigns with status/type filters and sortable columns. Returns counts per status tab (all/active/past/draft) and per type (retainer/challenge/leaderboard).
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 20 |
Status (string) or Status (null) (Status) UI alias: 'active' (= published), 'past' (= ended), 'draft' (= unpublished drafts), or 'archived'. | |
CampaignType (string) or Campaign Type (null) (Campaign Type) Filter: retainer | challenge | leaderboard | live_gmv_challenge. | |
Search (string) or Search (null) (Search) | |
Date From (string) or Date From (null) (Date From) YYYY-MM-DD; start_date >= date_from | |
Date To (string) or Date To (null) (Date To) YYYY-MM-DD; end_date <= date_to | |
Sort By (string) or Sort By (null) (Sort By) campaign_name | campaign_type | gmv | start_date | end_date | total_posts | total_views | created_at | |
| sort_order | string (Sort Order) ^(asc|desc)$ Default: "desc" |
nullCreate a Retainer / Challenge / Leaderboard / Live GMV Challenge campaign. X-Dry-Run: true validates the body and echoes what would be submitted without writing any rows. Image fields take HTTPS URL strings — host the image yourself and pass the URL.
The 201 response includes an invite_link field — the public URL the caller can share with creators to bring them into the campaign. Subdomain is picked by creator_source: legacy social_army campaigns use https://soco.reacherapp.com; everything else (my_community, etc.) uses https://creator.reacherapp.com. Full pattern: {base}/campaigns/{shop_id}/{uuid_id}. Every campaign endpoint that returns a campaign payload carries the same field — POST, GET list, GET single, GET detail — so callers can lift it directly without constructing the URL themselves.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| campaign_name required | string (Campaign Name) <= 255 characters |
| campaign_type required | string (CampaignType) Enum: "retainer" "challenge" "leaderboard" "live_gmv_challenge" Supported campaign types. |
| creator_source required | string (CreatorSource) Enum: "my_community" "social_army" How creators are sourced for a campaign. |
| start_date required | string (Start Date) |
End Date (string) or End Date (null) (End Date) YYYY-MM-DD. REQUIRED for challenge / leaderboard / live_gmv_challenge campaigns (the portal launch form requires an end date for these); optional only for retainer campaigns, which may run open-ended. | |
Description (string) or Description (null) (Description) REQUIRED for launch. Rich-text (HTML) campaign description shown to creators. Must contain visible text — an empty string or HTML-only value like ' ' is rejected, matching the portal launch form. | |
| status | string (CampaignStatus) Default: "published" Enum: "published" "draft" "deleted" "archived" DB-level campaign status. The frontend filter param 'active'/'past' are UI aliases — 'active' maps to published, 'past' maps to != published. |
required | any (Pricing) |
CampaignProducts (object) or null REQUIRED for launch. The portal launch form needs at least one product: send products.all_selected=true to include every shop product, or products.items=[...] with 1-10 products. | |
Array of Creators (objects) or Creators (null) (Creators) Optional list of creators to seed into the campaign. Mirrors the portal's contract exactly (see | |
Window Url (string) or Window Url (null) (Window Url) HTTPS URL — public landing/preview page for this campaign. | |
| is_available_to_all | boolean (Is Available To All) Default: false |
| requires_approval | boolean (Requires Approval) Default: false |
Array of Creator Level (strings) or Creator Level (string) or Creator Level (null) (Creator Level) Creator tier filter (list or CSV string). | |
Support Email (string) or Support Email (null) (Support Email) | |
Short Header Message (string) or Short Header Message (null) (Short Header Message) REQUIRED for launch. Short headline shown on the campaign card. Must be a non-empty string — the portal launch form rejects a blank value. | |
Content Guidelines (object) or Content Guidelines (null) (Content Guidelines) | |
Array of Inspiration Links (strings) or Inspiration Links (null) (Inspiration Links) List of HTTPS URLs (inspiration videos, mood-boards, etc.). | |
| has_tiered_payout | boolean (Has Tiered Payout) Default: false |
Payout Structure (object) or Payout Structure (null) (Payout Structure) | |
Grace Period (integer) or Grace Period (null) (Grace Period) | |
CampaignReminders (object) or null | |
CampaignEmailTemplates (object) or null |
{- "campaign_name": "string",
- "campaign_type": "retainer",
- "creator_source": "my_community",
- "start_date": "string",
- "end_date": "string",
- "description": "string",
- "status": "published",
- "pricing": {
- "campaign_type": "retainer",
- "posts": 1,
- "payment_per_creator": 0,
- "reward_type": "cash",
- "metric_type": "gmv",
- "minimum_gmv_required": 0,
- "minimum_gmv_required_enabled": false,
- "minimum_views_required": 0,
- "minimum_views_required_enabled": false,
- "minimum_videos_required": 0
}, - "products": {
- "all_selected": false,
- "items": [
- {
- "product_id": "string",
- "tap_link": "string",
- "product_name": "string"
}
], - "use_first_product_image": true,
- "custom_image": "string",
- "campaign_image": "string"
}, - "creators": [
- {
- "property1": "string",
- "property2": "string"
}
], - "window_url": "string",
- "is_available_to_all": false,
- "requires_approval": false,
- "creator_level": [
- "string"
], - "support_email": "string",
- "short_header_message": "string",
- "content_guidelines": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}, - "inspiration_links": [
- "string"
], - "has_tiered_payout": false,
- "payout_structure": { },
- "grace_period": 365,
- "reminders": {
- "enabled": false,
- "message_before_3_days": "string",
- "message_before_1_day": "string"
}, - "email_templates": {
- "enabled": true,
- "application": { },
- "acceptance": { },
- "rejection": { }
}
}{- "campaign_id": 0,
- "uuid_id": "string",
- "status": "created",
- "invite_link": "string"
}All creators currently linked to the shop's campaigns. Includes overview metrics (total creators, multi-campaign creators, overall Return-On-Campaign-Spend) plus a paginated per-creator list.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 20 |
Search (string) or Search (null) (Search) | |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_order | string (Sort Order) ^(asc|desc)$ Default: "desc" |
nullAll videos posted by creators across the shop's campaigns. Returns overview metrics (total posts, views, orders, GMV, wallet balance) plus a paginated content list. Use the campaign-detail endpoint for a campaign-scoped view.
| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 20 |
Search (string) or Search (null) (Search) | |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_order | string (Sort Order) ^(asc|desc)$ Default: "desc" |
null| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 20 |
Search (string) or Search (null) (Search) | |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_order | string (Sort Order) ^(asc|desc)$ Default: "desc" |
null| page | integer (Page) >= 1 Default: 1 |
| page_size | integer (Page Size) [ 1 .. 100 ] Default: 20 |
Sort By (string) or Sort By (null) (Sort By) | |
| sort_order | string (Sort Order) ^(asc|desc)$ Default: "desc" |
nullModify campaign fields. campaign_type and creator_source are immutable post-create — pass them and you'll get 400 IMMUTABLE_FIELD.
| campaign_id required | integer (Campaign Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
Campaign Name (string) or Campaign Name (null) (Campaign Name) | |
Start Date (string) or Start Date (null) (Start Date) | |
End Date (string) or End Date (null) (End Date) | |
Description (string) or Description (null) (Description) | |
CampaignStatus (string) or null | |
Pricing (any) or Pricing (null) (Pricing) | |
CampaignProducts (object) or null | |
Array of Creators (objects) or Creators (null) (Creators) Optional list of creators to seed into the campaign. Mirrors the portal's contract exactly (see | |
Window Url (string) or Window Url (null) (Window Url) | |
Is Available To All (boolean) or Is Available To All (null) (Is Available To All) | |
Requires Approval (boolean) or Requires Approval (null) (Requires Approval) | |
Array of Creator Level (strings) or Creator Level (string) or Creator Level (null) (Creator Level) | |
Support Email (string) or Support Email (null) (Support Email) | |
Short Header Message (string) or Short Header Message (null) (Short Header Message) | |
Content Guidelines (object) or Content Guidelines (null) (Content Guidelines) | |
Array of Inspiration Links (strings) or Inspiration Links (null) (Inspiration Links) | |
Has Tiered Payout (boolean) or Has Tiered Payout (null) (Has Tiered Payout) | |
Payout Structure (object) or Payout Structure (null) (Payout Structure) | |
Grace Period (integer) or Grace Period (null) (Grace Period) | |
CampaignReminders (object) or null | |
CampaignEmailTemplates (object) or null |
{- "campaign_name": "string",
- "start_date": "string",
- "end_date": "string",
- "description": "string",
- "status": "published",
- "pricing": {
- "campaign_type": "retainer",
- "posts": 1,
- "payment_per_creator": 0,
- "reward_type": "cash",
- "metric_type": "gmv",
- "minimum_gmv_required": 0,
- "minimum_gmv_required_enabled": false,
- "minimum_views_required": 0,
- "minimum_views_required_enabled": false,
- "minimum_videos_required": 0
}, - "products": {
- "all_selected": false,
- "items": [
- {
- "product_id": "string",
- "tap_link": "string",
- "product_name": "string"
}
], - "use_first_product_image": true,
- "custom_image": "string",
- "campaign_image": "string"
}, - "creators": [
- {
- "property1": "string",
- "property2": "string"
}
], - "window_url": "string",
- "is_available_to_all": true,
- "requires_approval": true,
- "creator_level": [
- "string"
], - "support_email": "string",
- "short_header_message": "string",
- "content_guidelines": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}, - "inspiration_links": [
- "string"
], - "has_tiered_payout": true,
- "payout_structure": { },
- "grace_period": 365,
- "reminders": {
- "enabled": false,
- "message_before_3_days": "string",
- "message_before_1_day": "string"
}, - "email_templates": {
- "enabled": true,
- "application": { },
- "acceptance": { },
- "rejection": { }
}
}{- "campaign_id": 0,
- "status": "updated"
}Sets status='deleted'. The row remains in the DB but is hidden from list/detail views. Idempotent.
| campaign_id required | integer (Campaign Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
{- "campaign_id": 0,
- "status": "deleted"
}Full campaign detail: campaign metadata, applied/active creators with stage + payment-due + per-creator actions, aggregated stats (GMV, views, orders, payouts), and a content snippet. Equivalent to what the portal's campaign-detail page renders.
| campaign_id required | integer (Campaign Id) >= 1 |
nullSets the creator's CampaignCreatorMapping.status='active'. Sends an acceptance email + SMS to the creator (fire-and-forget) — these are SKIPPED on X-Dry-Run: true.
| campaign_id required | integer (Campaign Id) >= 1 |
| creator_id required | integer (Creator Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
Message (string) or Message (null) (Message) Optional custom message included in the creator's acceptance email/SMS. If omitted, the campaign's default acceptance template is used. |
{- "message": "string"
}{- "success": true,
- "code": "ok",
- "data": { }
}Sets CampaignCreatorMapping.status='rejected'. Sends a rejection email + SMS to the creator (fire-and-forget) — SKIPPED on dry-run.
| campaign_id required | integer (Campaign Id) >= 1 |
| creator_id required | integer (Creator Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
Message (string) or Message (null) (Message) Optional custom message included in the creator's rejection email/SMS. |
{- "message": "string"
}{- "success": true,
- "code": "ok",
- "data": { }
}Reverses a reject: status goes back to active. No new notification is sent.
| campaign_id required | integer (Campaign Id) >= 1 |
| creator_id required | integer (Creator Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
{- "success": true,
- "code": "ok",
- "data": { }
}Removes the creator from ONE campaign (terminal removed status). The campaign lives in the x-shop-id shop; pass its id in the body. Removed creators disappear from the creator's portal views.
Paid/completed creators are blocked (409) — their payout ledger is preserved and never overwritten.
Idempotent: removing an already-removed creator returns 200 with code='already_removed' (no error). Combined with the Idempotency-Key replay, repeated calls are always safe.
X-Dry-Run: true validates + echoes the intended action without writing or sending the optional SMS.
| creator_id required | integer (Creator Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| campaign_id required | integer (Campaign Id) > 0 Campaign (in the x-shop-id shop) to remove the creator from. |
Message (string) or Message (null) (Message) Optional SMS sent to the creator on removal. Removal is otherwise silent (no email, no default SMS). Length capped at 320 to match the service's SMS limit. SKIPPED on X-Dry-Run. |
{- "campaign_id": 0,
- "message": "string"
}{- "success": true,
- "code": "ok",
- "data": { }
}Adds the creator to a target campaign — purely additive (never removes them from the source campaign). The SOURCE shop is your x-shop-id; the TARGET shop + campaign are in the body.
Restrictions:
pg_advisory_xact_lock guards it; a paid_at row is never overwritten).Rewards are recomputed server-side from the TARGET campaign. notify (default true) sends the creator an acceptance-style notification — SKIPPED on X-Dry-Run.
| creator_id required | integer (Creator Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| target_campaign_id required | integer (Target Campaign Id) > 0 Campaign the creator is being added to (lives in target_shop_id). |
| target_shop_id required | integer (Target Shop Id) > 0 Shop that owns the target campaign. Must belong to the same customer as your API key (else 404). |
| notify | boolean (Notify) Default: true Send the creator an acceptance-style notification on add. SKIPPED on X-Dry-Run. |
{- "target_campaign_id": 0,
- "target_shop_id": 0,
- "notify": true
}{- "success": true,
- "code": "ok",
- "data": { }
}| video_id required | string (Video Id) [ 1 .. 64 ] characters |
{- "video_id": "string"
}{- "status": "success",
- "data": [
- { }
], - "count": 0
}Used by the settlement screen to enumerate the videos a creator posted under a specific campaign.
| campaign_creator_mapping_id required | integer (Campaign Creator Mapping Id) > 0 |
{- "campaign_creator_mapping_id": 0
}{- "status": "success",
- "data": [
- { }
], - "count": 0
}Soft-deletes a CampaignCreatorMapping's content tracker so it no longer surfaces in campaign content lists.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| campaign_creator_mapping_id required | integer (Campaign Creator Mapping Id) > 0 |
{- "campaign_creator_mapping_id": 0
}{- "status": "string",
- "message": "string"
}Updates the creator's posts requirement and minimum GMV target on their CampaignCreatorMapping, then fires a notification (email + SMS) asking for additional posts — notifications SKIPPED on dry-run.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| creator_id required | integer (Creator Id) > 0 |
| campaign_creator_mapping_id required | integer (Campaign Creator Mapping Id) > 0 |
| campaign_id required | integer (Campaign Id) > 0 |
| additional_posts required | integer (Additional Posts) [ 1 .. 100 ] |
required | New Total Payout (number) or New Total Payout (string) (New Total Payout) New total payout — number for cash campaigns, string label (e.g. 'free product') for custom-reward campaigns. |
| minimum_gmv_target required | number (Minimum Gmv Target) > 0 |
Tiktok Username (string) or Tiktok Username (null) (Tiktok Username) | |
CreatorStatus (string) or null |
{- "creator_id": 0,
- "campaign_creator_mapping_id": 0,
- "campaign_id": 0,
- "additional_posts": 1,
- "new_total_payout": 0,
- "minimum_gmv_target": 0,
- "tiktok_username": "string",
- "creator_status": "pending"
}{- "status": "success"
}Returns a Stripe Checkout session_id + redirect_url. Creating the intent does NOT move money — money moves only when the user completes the hosted checkout. X-Dry-Run: true validates the body without calling Stripe.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| amount required | number (Amount) ( 0 .. 100000 ] |
| currency | string (Currency) = 3 characters Default: "USD" ISO 4217 currency. The wallet's persisted currency overrides this for cross-currency safety. |
| success_url required | string (Success Url) <= 2048 characters URL Stripe redirects to on completion. Must use a Reacher-controlled host (app.reacherapp.com, portal.reacherapp.com, staging.reacherapp.com) or localhost/127.0.0.1 for development. |
| cancel_url required | string (Cancel Url) <= 2048 characters |
{- "amount": 100000,
- "currency": "USD",
- "success_url": "string",
- "cancel_url": "string"
}{- "session_id": "string",
- "redirect_url": "string"
}Triggers a real Stripe transfer + wallet debit when reward_type='cash'. reward_type='custom' records the settlement only — no money moves. Idempotency-Key is REQUIRED and the inner PaymentService.settle runs claim/release semantics so a retry with the same key can never double-pay. Every successful settlement emits an audit.campaigns.settle log line for on-call reconciliation. X-Dry-Run: true skips the Stripe call entirely.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| creator_id required | integer (Creator Id) > 0 |
| campaign_id required | integer (Campaign Id) > 0 |
| amount required | number (Amount) ( 0 .. 100000 ] Settlement amount in the campaign's currency. Capped at $100,000 per call as a sanity guard. |
| currency required | string (Currency) = 3 characters ISO 4217 currency code (e.g. 'USD'). Informational — the shop's persisted wallet currency takes precedence at settlement time. If the wallet currency differs from this value, the transfer executes in the wallet currency without rejection. The response's |
| reward_type required | string (Reward Type) ^(cash|custom)$ 'cash' triggers a Stripe transfer + wallet debit; 'custom' records the settlement only (no money moves). |
| campaign_creator_mapping_id required | integer (Campaign Creator Mapping Id) > 0 REQUIRED. The campaign-creator mapping id that the settlement is being recorded against. The portal surfaces this id on every creator row in |
Metadata (object) or Metadata (null) (Metadata) Free-form metadata stored alongside the settlement (e.g. agent annotation, internal reference). |
{- "creator_id": 0,
- "campaign_id": 0,
- "amount": 100000,
- "currency": "str",
- "reward_type": "string",
- "campaign_creator_mapping_id": 0,
- "metadata": { }
}{- "success": true,
- "transfer_id": "string",
- "amount": 0,
- "currency": "string",
- "paid_at": "string",
- "wallet_balance": 0
}Sets status='archived' — preserves the row in list/detail views but marks it as no longer active.
| campaign_id required | integer (Campaign Id) >= 1 |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
{- "campaign_id": 0,
- "status": "archived"
}Upload a list of creator handles + emails. Two paths: JSON body OR multipart CSV (file field name file, columns creator_name required + email optional). Returned list_id is what callers pass to automations as lists_selected.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| name required | string (Name) [ 1 .. 120 ] characters Human-readable list name shown in the portal. |
Description (string) or Description (null) (Description) | |
| creator_handles | Array of strings (Creator Handles) <= 50000 items TikTok handles, with or without leading '@'. Deduplicated case-insensitively at insert time. |
| creator_emails | Array of strings (Creator Emails) <= 50000 items Email addresses. Deduplicated case-insensitively at insert time. |
{- "name": "string",
- "description": "string",
- "creator_handles": [
- "string"
], - "creator_emails": [
- "string"
]
}{- "data": {
- "list_id": "string",
- "name": "string",
- "description": "string",
- "creator_count": 0,
- "email_count": 0,
- "state": "string",
- "created_at": "string",
- "updated_at": "string"
}
}| page | integer (Page) Default: 1 |
| page_size | integer (Page Size) Default: 50 |
Name Contains (string) or Name Contains (null) (Name Contains) |
{- "data": [
- {
- "list_id": "string",
- "name": "string",
- "description": "string",
- "creator_count": 0,
- "email_count": 0,
- "state": "string",
- "created_at": "string",
- "updated_at": "string"
}
], - "pagination": null
}| list_id required | integer (List Id) |
{- "data": {
- "list_id": "string",
- "name": "string",
- "description": "string",
- "creator_count": 0,
- "email_count": 0,
- "state": "string",
- "created_at": "string",
- "updated_at": "string"
}, - "creator_handles": [
- "string"
], - "creator_emails": [
- "string"
]
}Sets state=archived. Idempotent — already-archived returns 200.
| list_id required | integer (List Id) |
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
nullPaginated list of CRM Groups for this shop — creator cohorts you can target or exclude in automations. Membership is live for filter-built groups and frozen for groups built from a dashboard segment; see conditions on each group. Create segment-based groups with POST /crm-groups/from-segment; filter-built groups are still portal-only.
| page | integer (Page) Default: 1 |
| page_size | integer (Page Size) Default: 50 |
Name Contains (string) or Name Contains (null) (Name Contains) |
{- "data": [
- {
- "crm_group_id": "string",
- "name": "string",
- "description": "string",
- "conditions": [
- {
- "field": "string",
- "operator": "string",
- "value": null,
- "value_count": 0
}
], - "creator_count": 0,
- "last_synced_at": "string"
}
], - "pagination": null
}Build a group from a Creators-tab segment — a GMV tier, an automation_id, and a date window — rather than from raw filter conditions. Use it to turn 'creators in tier L3 reached by automation 812 last month' into a reusable cohort you can target with an automation.
Membership is a snapshot. Members are materialized once at creation and do not update as creators enter or leave the segment. Re-post to refresh.
The window is always bounded. Omit start_date/end_date and the segment resolves over the trailing 28 days rather than the shop's whole history; the maximum span is 365 days. Pass both dates explicitly whenever the segment you have in mind is a specific period.
Creation upserts by name. Reusing an existing group_name in this shop overwrites that group's definition and replaces its members.
Expect fewer creators than the dashboard shows. Only CRM-tracked creators can be grouped, so DM-only and organic creators in the segment resolve to nothing. handles_resolved is what the segment matched; creator_count is what made it into the group. The gap between them is that drop-off — check it before treating the group as the segment.
X-Dry-Run: true reports the segment size and whether it exceeds the group limit, without writing. It cannot show the CRM drop-off: that is only known once the group is built.
Idempotency-Key (string) or Idempotency-Key (null) (Idempotency-Key) | |
X-Dry-Run (string) or X-Dry-Run (null) (X-Dry-Run) |
| group_name required | string (Group Name) [ 1 .. 255 ] characters Name for the new group. Creation upserts by (shop, group_name) — reusing a name overwrites that group's definition and re-materializes its members. |
Tier (string) or Tier (null) (Tier) GMV tier code to narrow the segment, e.g. 'L3'. Omit for all tiers. | |
Automation Id (integer) or Automation Id (null) (Automation Id) Restrict the segment to creators reached by this automation. | |
Start Date (string) or Start Date (null) (Start Date) Segment window start (inclusive). | |
End Date (string) or End Date (null) (End Date) Segment window end (inclusive). | |
Array of Group Tags (strings) or Group Tags (null) (Group Tags) Optional tags to attach to the group. |
{- "group_name": "string",
- "tier": "string",
- "automation_id": 1,
- "start_date": "2019-08-24",
- "end_date": "2019-08-24",
- "group_tags": [
- "string"
]
}{- "data": {
- "crm_group_id": "string",
- "name": "string",
- "creator_count": 0,
- "handles_resolved": 0,
- "group_tags": [
- "string"
]
}, - "dry_run": true
}| crm_group_id required | string (Crm Group Id) |
{- "data": {
- "crm_group_id": "string",
- "name": "string",
- "description": "string",
- "conditions": [
- {
- "field": "string",
- "operator": "string",
- "value": null,
- "value_count": 0
}
], - "creator_count": 0,
- "last_synced_at": "string"
}
}