{
  "openapi": "3.1.0",
  "info": {
    "title": "Cruva API",
    "version": "1.0.0",
    "summary": "Programmatic access to Cruva: TikTok Shop affiliates, creator outreach, samples, content, ads, and analytics.",
    "description": "The Cruva API lets you read and act on your Cruva shops: shop stats and products, affiliates (CRM), videos and LIVEs, sample requests, creator DMs and outreach automations, email campaigns, lists, groups, workflows, creator briefs, community campaigns, TikTok and Meta ads, and halo-effect reporting. Enterprise endpoints add cross-shop market intelligence on brands, products, and creators.\n\n## Authentication\n\nAll API requests require the following headers. Send your API key in `x-api-key` and the Cruva shop ID in `x-shop-id`. Create keys at https://cruva.com/dashboard/api.\n\nThe x-shop-id header is a Cruva internal shop ID — it is not the same as your TikTok shop ID/code. To find it: (1) go to cruva.com/dashboard/my-shops, (2) click the dropdown on the right of the shop and choose View Info, (3) copy the Shop ID from the popup.\n\n## Permissions\n\nEach API key can be restricted to specific routes and specific shops. Every operation's `security` requirement names the route permission it needs (format `<METHOD> <path>`); the full catalogue is in the `apiKey` scheme's `x-scopes`. A key without the permission, or used with a shop outside its allowed shops, receives `403`.\n\n## Tiers\n\n**Standard API:** Included in the standard Cruva API subscription ($399/month, account-wide across all shops). Every endpoint tagged `tier: \"standard\"` is callable with a Standard API key.\n\n**Enterprise API:** Endpoints tagged `tier: \"enterprise\"` are part of a separate Enterprise tier and are NOT included in the standard subscription. They expose proprietary market intelligence and creator analytics (cross-shop brand/product/creator data) that require a custom plan. A Standard API key cannot call these endpoints — calls will fail with an authorization error until your account is upgraded. Every enterprise endpoint takes a `region` field selecting which TikTok Shop market to query. Pass exactly one of the values in `supported_regions` (lowercase ISO-style country code). Supported regions: `us`, `uk`, `mx`, `es`, `de`, `ie`, `it`, `fr`, `nl`, `pt`, `gr`, `be`, `at`, `pl`, `hu`, `cz`, `br`, `jp`.\n\n## Usage limits\n\n**Rate limits.** Each API key may make up to **10 requests per second** and **1,000,000 requests per day**, measured per shop. Requests past either threshold receive a `429 Too Many Requests`; back off briefly and retry.\n\n**Maximum pagination depth.** Paginated endpoints return results up to a depth of **10,000 rows**. Once `page_number × page_size` (or repeated cursor paging) would reach beyond that point, no further rows are returned. To access records past the cap, narrow the result set with filters rather than paging deeper.\n\nThese limits are standard, canonical safeguards used across virtually every production data API. They exist to protect the underlying databases from queries that scan unbounded numbers of rows. The Cruva API is designed to serve targeted, filtered reads — it is not intended to be swept continuously to mirror or replicate an entire dataset.\n\n**Keeping a local copy in sync?** Query deliberately. Scope each request with filters (date ranges, status, specific handles or IDs) and page only as deep as you actually need. On subsequent syncs, fetch and update only the records that have changed rather than re-pulling everything. A targeted, incremental approach stays comfortably within these limits and is faster and more reliable than repeatedly reading the full dataset.\n\n## Idempotency\n\nOpt in to idempotent writes by sending an **`Idempotency-Key`** header alongside any supported write request. The key must match `^[A-Za-z0-9-]{1,128}$` (letters, digits, dashes, up to 128 chars).\n\n**How it works:** the server caches the response `(status, body)` for **24 hours** under a key scoped to your shop. A replay with the same `Idempotency-Key` returns the **original response byte-for-byte** — same `campaign_id`, same timestamps, same status code. Concurrent requests with the same key receive a `409` for up to **60 seconds** while the first one is in flight. `5xx` responses and uncaught exceptions are **not** cached — a retry can still succeed.\n\n**Supported endpoints:** `POST /automations/create`, `POST /automations/update`, `DELETE /automations/delete`, `POST /emails/campaigns/create`, `POST /emails/campaigns/update`, `DELETE /emails/campaigns/delete`, `POST /emails/senders/create-custom`, `POST /groups/create`, `DELETE /groups/delete`, `POST /lists/create`, `POST /lists/merge`, `DELETE /lists/delete`, `POST /creator-briefs/create`, `POST /creator-briefs/update`, `DELETE /creator-briefs/delete`, `POST /community/campaigns/create`, `POST /community/campaigns/update`, `DELETE /community/campaigns/delete`, `POST /affiliate/samples/approve`, `POST /affiliate/samples/reject`, `POST /affiliate/samples/ignore`, `POST /affiliate/samples/unignore`, `POST /affiliate/message/dm`. Omitting the header on any of these is fine — the endpoint behaves normally with no caching.\n\n**Community payouts** are idempotent by design without the header: `/community/payouts/authorize` is keyed on (campaign, creator, period) — a repeat call returns `400 already paid` rather than double-paying.",
    "termsOfService": "https://cruva.com/terms",
    "contact": {
      "name": "Cruva support",
      "email": "support@cruva.com",
      "url": "https://cruva.com/developers"
    }
  },
  "externalDocs": {
    "description": "Cruva API reference",
    "url": "https://cruva.com/docs/api"
  },
  "servers": [
    {
      "url": "https://api.cruva.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Idempotency",
      "description": "Idempotency endpoints (Standard API)."
    },
    {
      "name": "Account",
      "description": "Account endpoints (Standard API)."
    },
    {
      "name": "Products",
      "description": "Products endpoints (Standard API, Enterprise API)."
    },
    {
      "name": "Analytics",
      "description": "Analytics endpoints (Standard API)."
    },
    {
      "name": "Shop health",
      "description": "Shop health endpoints (Standard API)."
    },
    {
      "name": "Halo Effect",
      "description": "The dashboard's **Content → Halo Effect** page as an API: how your TikTok activity (video views, TikTok Shop GMV) lines up with your sales **off TikTok** on a connected Shopify store and Amazon account.\n\n[Halo Effect - Report](https://cruva.com/docs/api#halo-effect-report) returns everything the page shows in one call — the four KPI cards, TikTok totals, per-platform totals and campaign lift, and a daily (or weekly/monthly) chart series. [Halo Effect - Product Links](https://cruva.com/docs/api#halo-effect-product-links) lists which stores are connected and which TikTok products are linked to which Shopify products/variants or Amazon ASINs; pass one of its `tiktok_product_id`s to the report to narrow it to that product.\n\n**Connecting stores and linking products happens in the dashboard.** These endpoints are read-only.\n\n**Missing data is `null`, not `0`.** When a platform isn't part of the report (not connected, not linked, still refreshing, failed) or has no data for a day, that day's revenue for the platform is `null` and the day is left out of the halo stats rather than counted as a day with no sales. Each platform block carries `warnings` whenever its numbers are partial — read them before treating a total as complete.\n\n**Shopify numbers are snapshots** refreshed nightly (and on demand). If a store has no snapshot yet, the first call starts a refresh and returns the Shopify block with `status: \"refreshing\"`; call again in a few minutes. A snapshot older than 6 hours is served as-is while a refresh runs in the background. **Amazon numbers** come live from the Selling Partner API and are cached for up to 12 hours."
    },
    {
      "name": "CRM & Content",
      "description": "CRM & Content endpoints (Standard API)."
    },
    {
      "name": "TikTok Ads",
      "description": "Endpoints for paid TikTok performance: shared **Spark ad** codes plus **GMV Max** campaign, creative, exclusion, and boost analytics.\n\nTo drill from a campaign into its creatives, take the campaign's `campaign_id` from **GMV Max - List Campaigns** and pass it to **GMV Max - List Creatives**. Use **List Excluded Creatives** and **List Boosted Creatives** for the same activity lists shown in the dashboard's Excluded and Boosted tabs.\n\n**Note:** Spark video matching and GMV Max creative metadata require the TikTok for Business API to be installed on the brand. Without it, the joined `video_data` / content fields are returned as `null`.\n\nFor Instagram/Facebook partnership ads pushed from Cruva, see the **Meta Ads** section below."
    },
    {
      "name": "Meta Ads",
      "description": "Analytics for the **Meta Ads suite**: Instagram/Facebook partnership ads created by pushing creator TikTok videos from Cruva, and the creator **programs** those videos come from.\n\n**Scope — Cruva-pushed ads only.** These endpoints are **not** a mirror of your whole Meta Ads account. Performance comes from a daily ClickHouse mirror covering the ads pushed through Cruva (the Meta Ads programs / licensed-content push flow) and the campaigns and ad sets they live in. Ads created directly in Meta Ads Manager and never pushed through Cruva generally do not appear — and in campaigns that mix both, non-Cruva entities can surface as raw Meta ids with `null` names, because display names are stamped at push time.\n\n**Drill-down:** [List Campaigns](https://cruva.com/docs/api#meta-campaigns) → pass `campaign_id` to [List Ad Sets](https://cruva.com/docs/api#meta-adsets) → pass `adset_id` to [List Ads](https://cruva.com/docs/api#meta-ads). Programs live in [List Programs](https://cruva.com/docs/api#meta-programs); pass a `program_id` to [List Program Creators](https://cruva.com/docs/api#meta-program-creators) or to any of the ads endpoints to scope metrics to one program.\n\n**Revenue caveat:** `purchase_value` (and `sales` on programs) is **Meta-attributed** purchase value — it requires the brand's site to send purchase events via the Pixel or Conversions API. TikTok Shop sales do not appear in these fields."
    },
    {
      "name": "Sample Requests",
      "description": "Sample Requests endpoints (Standard API)."
    },
    {
      "name": "Outreach",
      "description": "Outreach endpoints (Standard API)."
    },
    {
      "name": "Automations",
      "description": "The `outreach_filters` object on `/automations/create` (audience `new_affiliates`) selects creators from the **platform-wide creator index**. All fields are optional and combine with AND; array fields match OR within the field.\n\n**Numeric range fields** (send either or both bounds):\n`follower_min` / `follower_max` — follower count.\n`min_gmv` / `max_gmv` — the creator's platform-wide affiliate GMV over the last 30 days, across all brands. This is the creator-tier basis (L0-L7), **not** their GMV with your shop.\n`min_live_gmv` / `max_live_gmv` — LIVE-stream GMV over the last 30 days.\n`engagement` / `max_engagement` — video engagement rate in percent (`5` = 5%). `engagement` is the lower bound.\n`avg_view_cnt` / `max_avg_view_cnt` — average video views. `avg_view_cnt` is the lower bound.\n`post_rate` — minimum posting rate, percent.\n`brand_collaborations` / `max_brand_collaborations` — number of brand collaborations.\n`min_pps` / `max_pps` — promotion performance score, 0-5.\n`min_content_quality` / `max_content_quality` — content quality score, 0-100.\n`min_live_avg_view_cnt` / `max_live_avg_view_cnt` — average viewers on shoppable LIVEs.\n`min_creator_rating` / `max_creator_rating` — seller-given creator rating, 0-5.\n`min_sample_score` / `max_sample_score` — TikTok sample score, 0-100.\n`min_posts_with_samples` / `max_posts_with_samples`, `min_post_frequency` / `max_post_frequency`, `min_sales_generation` / `max_sales_generation` — the sample score's components, each 0-100.\n`is_fast_growing` — boolean.\n\n**Value-list fields** — expand each reference below for the exact accepted strings. Values are matched case-insensitively for the demographic/appearance fields.\n\n**Caps:** the audience estimator silently drops `categories` past 5 entries, and `units_sold` / `follower_ages` past 2 entries — stay within those.\n\n**Deprecated:** the legacy `gmv_ranges` and `live_gmv` bucket arrays still exist on old automations but should never be sent — always use the numeric `min_gmv`/`max_gmv` and `min_live_gmv`/`max_live_gmv` bounds."
    },
    {
      "name": "Email Campaigns",
      "description": "Email Campaigns endpoints (Standard API)."
    },
    {
      "name": "Groups",
      "description": "Groups are saved CRM segments — a named, reusable filter that resolves to a set of creators. Reference a group from an automation by setting `outreach_audience: \"groups\"` and passing the group's `group_id` on `/automations/create`."
    },
    {
      "name": "Lists",
      "description": "Lists are named sets of creator **handles** — the audiences behind `outreach_audience: \"list\"` automations. Unlike [Groups](https://cruva.com/docs/api#groups-list) (which are saved *filters* that re-resolve dynamically), a list is a fixed roster: exactly the creators you put in it.\n\nA list is identified by its **title** within your shop — there is no separate list id. Creating into an existing title **appends**; re-adding a handle already in the list is a silent no-op.\n\n**Handles are normalized and verified.** Every handle is trimmed, stripped of a leading `@`, lowercased, and validated against `[a-z0-9._]` (max 30 chars). Handles are then resolved against Cruva's creator index — handles that don't match a known TikTok Shop creator are skipped and reported back in `unmatched` (they couldn't be messaged anyway).\n\n**Every list-creating endpoint caps at 10,000 creators per call** and reports `added_count`, so you always know exactly what was written."
    },
    {
      "name": "Tags",
      "description": "Tags are free-text labels on creators in your CRM — the same chips you see on the CRM table, and what `include_tags` / `exclude_tags` filter on in `/affiliate/crm/list`. There is no separate tag object: tagging a creator with a new name creates the tag, and a tag with no creators left disappears. Creators are addressed by TikTok handle and must already be in the shop's CRM. Tag names are 1–60 characters, case preserved (`VIP` and `vip` are different tags). Dynamic tags configured in the dashboard are recomputed from a saved group on every CRM refresh and will drop creators added by hand under the same name."
    },
    {
      "name": "Workflows",
      "description": "Workflows are the multi-step creator journeys built in the dashboard's Workflows builder: a trigger (a creator-matching filter, or a recurring schedule), then a graph of steps — DMs, TikTok invites, emails, waits, conditions, tags, lists. The API lets you **read, create, pause/activate and delete** workflows by `workflow_id`; editing an existing step graph is done in the builder, which re-points creators already inside it. Workflows are a Scale-plan feature: reads work on any plan, but `toggle` returns `403` below Scale."
    },
    {
      "name": "Creator Briefs",
      "description": "Creator briefs are **shareable landing pages** you send to creators: example videos to emulate, proven opening hooks, do/don't guidelines, an optional info PDF, and links to your community hub and campaigns. Every brief gets a short public link — `cruva.com/fw?id=<code>`.\n\n**Using a brief in an automation is just a link.** Paste the brief's `link` into the automation's `invite_details.message` or a `dm_messages` item's `content` on [/automations/create](https://cruva.com/docs/api#automations-create) — e.g. `\"Hi [affiliate_name]! Here's everything you need to get started: cruva.com/fw?id=ab12cd\"`.\n\n**Two brief types:**\n**Static** — a fixed page. With `video_mode: \"manual\"` you pick the exact videos; with `\"auto\"` the page features the shop's current top videos per your sourcing rules.\n**Dynamic** — the page generates itself per product: creators pick one of your products and see its top videos and hooks live, always fresh.\n\nRequires the **Scale plan**; max **500** briefs per shop. Branding (logo, banner color) is shop-level and managed in the dashboard."
    },
    {
      "name": "Community",
      "description": "The community platform hosts creator contests and retainer deals on your public brand page at **creators.cruva.com**: races, contests, leaderboards, bingo boards, sweepstakes, and retainers. Every campaign gets a unique 6-character slug; its public **share link** is `https://creators.cruva.com/<slug>` — creators open that link to view and join the campaign.\n\nThe share link is designed to be dropped into outreach: create a campaign, take the `share_link` from the response, and reference it in an automation's DM or invite message (`/automations/create`) to invite creators at scale.\n\nCampaigns created here appear in the dashboard (Community → Campaigns) and go live on the public page immediately when `status` is `active`. Requires the **Scale plan**."
    },
    {
      "name": "Creators",
      "description": "Creators endpoints (Enterprise API)."
    },
    {
      "name": "Brands",
      "description": "Brands endpoints (Enterprise API)."
    },
    {
      "name": "Status",
      "description": "Service status. No API key required."
    }
  ],
  "paths": {
    "/idempotency/{key}": {
      "get": {
        "operationId": "idempotencyGet",
        "summary": "Idempotency - Lookup by Key",
        "description": "Retrieve a previously stored idempotent response by its key (scoped to the current shop via `x-shop-id`). Useful when a client loses connectivity mid-request and needs to recover the result without re-sending the original write.",
        "tags": [
          "Idempotency"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#idempotency-get"
        },
        "security": [
          {
            "apiKey": [
              "GET /idempotency/<key>"
            ]
          }
        ],
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "required": true,
            "description": "URL segment. The same string previously sent as `Idempotency-Key`.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9-]{1,128}$"
            }
          },
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "responses": {
          "200": {
            "description": "Response 200 (in-flight)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "idempotency": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "type": "string",
                          "description": "`processing` if a concurrent write holds the key, `completed` if the cached response is available."
                        },
                        "response_status": {
                          "type": "number",
                          "description": "HTTP status code of the original response. Only present when `status` is `completed`."
                        },
                        "response_body": {
                          "type": "object",
                          "properties": {
                            "data": {
                              "type": "object",
                              "properties": {
                                "campaign_id": {
                                  "type": "string"
                                },
                                "message": {
                                  "type": "string"
                                },
                                "messages_remaining": {
                                  "type": "number"
                                },
                                "status": {
                                  "type": "string"
                                }
                              }
                            }
                          },
                          "description": "The exact body returned by the original request. Only present when `status` is `completed`."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200_in_flight": {
                    "summary": "Response 200 (in-flight)",
                    "value": {
                      "idempotency": {
                        "status": "processing"
                      }
                    }
                  },
                  "Response_200_completed": {
                    "summary": "Response 200 (completed)",
                    "value": {
                      "idempotency": {
                        "status": "completed",
                        "response_status": 201,
                        "response_body": {
                          "data": {
                            "campaign_id": "6a14aa4f8c93e2105d7bf830",
                            "message": "Automation created.",
                            "messages_remaining": 3978511,
                            "status": "stopped"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "key format invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "key format invalid",
                    "value": {
                      "error": "Invalid idempotency key format"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "no stored response (never made, or TTL expired)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "no stored response (never made, or TTL expired)",
                    "value": {
                      "error": "No stored response for that key"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/account/shops": {
      "get": {
        "operationId": "shopsList",
        "summary": "List Shops",
        "description": "Retrieve every shop on your account — active or not — with `is_active` telling you which ones are live (`false` = paused, unpaid or cancelled). Use this to get the `shop_id` values you need for the `x-shop-id` header on every other endpoint.",
        "tags": [
          "Account"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#shops-list"
        },
        "security": [
          {
            "apiKey": [
              "GET /account/shops"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "shop_id": {
                            "type": "string"
                          },
                          "shop_name": {
                            "type": "string"
                          },
                          "is_active": {
                            "type": "boolean"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date"
                          },
                          "plan": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "shop_id": "a1b2c3d4e5f6g7h8i9j0k1l2",
                          "shop_name": "Example Shop One",
                          "is_active": true,
                          "created_at": "2024-06-29",
                          "plan": "scale"
                        },
                        {
                          "shop_id": "m3n4o5p6q7r8s9t0u1v2w3x4",
                          "shop_name": "Example Shop Two",
                          "is_active": true,
                          "created_at": "2025-06-10",
                          "plan": "scale"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/shop/products": {
      "post": {
        "operationId": "shopProducts",
        "summary": "List Shop Products",
        "description": "List the products that belong to a shop. Supports optional fuzzy search, filtering by open plan status, and sorting by price or units sold.",
        "tags": [
          "Products"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#shop-products"
        },
        "security": [
          {
            "apiKey": [
              "POST /shop/products"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "`search` — optional fuzzy search on product name. `is_open_plan` — `true` for open plan only, `false` for non-open plan only, `null` for all. `sort_by` — `price` or `units_sold` (default `units_sold`). `sort_direction` — `asc` or `desc` (default `desc`).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string"
                  },
                  "is_open_plan": {
                    "type": [
                      "boolean",
                      "null"
                    ]
                  },
                  "sort_by": {
                    "type": "string"
                  },
                  "sort_direction": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "search": "",
                "is_open_plan": null,
                "sort_by": "units_sold",
                "sort_direction": "desc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "product_id": {
                            "type": "string"
                          },
                          "product_name": {
                            "type": "string"
                          },
                          "status": {
                            "type": "number"
                          },
                          "is_open_plan": {
                            "type": "boolean"
                          },
                          "price": {
                            "type": "number"
                          },
                          "units_sold": {
                            "type": "number"
                          },
                          "stock": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "product_id": "1800291847362058192",
                          "product_name": "Glow Radiance Serum SPF30 – Hydrating Sun Shield",
                          "status": 1,
                          "is_open_plan": true,
                          "price": 850,
                          "units_sold": 4312,
                          "stock": 1204
                        },
                        {
                          "product_id": "1800384726159403248",
                          "product_name": "Velvet Matte Lipstick – Long Lasting Natural Finish",
                          "status": 1,
                          "is_open_plan": true,
                          "price": 420,
                          "units_sold": 1587,
                          "stock": 356
                        },
                        {
                          "product_id": "1800492618374920560",
                          "product_name": "Crystal Clear Eye Cream – Dark Circle Corrector",
                          "status": 1,
                          "is_open_plan": false,
                          "price": 690,
                          "units_sold": 923,
                          "stock": 89
                        },
                        {
                          "product_id": "1800571839205748208",
                          "product_name": "Berry Blush Duo – Cream & Powder Compact Set",
                          "status": 3,
                          "is_open_plan": true,
                          "price": 1150,
                          "units_sold": 45,
                          "stock": 0
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/shop/skus": {
      "post": {
        "operationId": "shopSkus",
        "summary": "List Shop SKUs",
        "description": "List the SKUs (product variants) that belong to a shop. Supports optional fuzzy search, filtering to a single product, and sorting by price or stock.",
        "tags": [
          "Products"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#shop-skus"
        },
        "security": [
          {
            "apiKey": [
              "POST /shop/skus"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "`search` — optional fuzzy search on SKU or product name. `product_id` — optional, filter to a single product's SKUs. `sort_by` — `price` or `stock` (default `stock`). `sort_direction` — `asc` or `desc` (default `desc`).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string"
                  },
                  "product_id": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "sort_by": {
                    "type": "string"
                  },
                  "sort_direction": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "search": "",
                "product_id": null,
                "sort_by": "stock",
                "sort_direction": "desc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "sku_id": {
                            "type": "string"
                          },
                          "sku_name": {
                            "type": "string"
                          },
                          "product_id": {
                            "type": "string"
                          },
                          "product_name": {
                            "type": "string"
                          },
                          "price": {
                            "type": "number"
                          },
                          "custom_cogs": {
                            "type": [
                              "number",
                              "null"
                            ]
                          },
                          "stock": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "sku_id": "1729382916473829105",
                          "sku_name": "Shade 01 – Ivory",
                          "product_id": "1800291847362058192",
                          "product_name": "Glow Radiance Serum SPF30 – Hydrating Sun Shield",
                          "price": 850,
                          "custom_cogs": 210,
                          "stock": 745
                        },
                        {
                          "sku_id": "1729382916473829106",
                          "sku_name": "Shade 02 – Beige",
                          "product_id": "1800291847362058192",
                          "product_name": "Glow Radiance Serum SPF30 – Hydrating Sun Shield",
                          "price": 850,
                          "custom_cogs": null,
                          "stock": 459
                        },
                        {
                          "sku_id": "1729471625384950217",
                          "sku_name": "Ruby Red",
                          "product_id": "1800384726159403248",
                          "product_name": "Velvet Matte Lipstick – Long Lasting Natural Finish",
                          "price": 420,
                          "custom_cogs": 95,
                          "stock": 356
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/timeseries/products": {
      "post": {
        "operationId": "tsProducts",
        "summary": "Product Timeseries Search",
        "description": "Search products by performance over a specific date range. Returns per-product GMV breakdowns (total, affiliate, video, live, shop tab), units sold, shop tab impressions, subscription metrics and price during the period. Supports filtering by product.",
        "tags": [
          "Products"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ts-products"
        },
        "security": [
          {
            "apiKey": [
              "POST /timeseries/products"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Subscription fields.** `subscription_gmv`, `new_subscriptions`, `active_subscriptions` and `recurring_subscriptions` are the only subscription metrics with a per-product breakdown — the shop-wide ones (retention rate, take rate, subscription AOV, active subscribers, one-time and recurring GMV) are available from `POST /shop/stats` instead. `subscription_gmv` and `new_subscriptions` are period totals, but `active_subscriptions` and `recurring_subscriptions` are **point-in-time** counts: each product reports its level on its own latest reporting day, not a total across the range. Those two are not additive — do not sum them across periods or across products.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "search_params": {
                    "type": "object",
                    "properties": {
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "product_id": {
                        "type": "string"
                      }
                    }
                  },
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "Object with `from` and `to` dates (YYYY-MM-DD)"
                  },
                  "sort_by": {
                    "type": "string",
                    "enum": [
                      "total_gmv",
                      "affiliate_gmv",
                      "video_gmv",
                      "live_gmv",
                      "shop_tab_gmv",
                      "shop_tab_impressions",
                      "units_sold",
                      "subscription_gmv",
                      "new_subscriptions",
                      "active_subscriptions",
                      "recurring_subscriptions"
                    ],
                    "description": "One of `total_gmv`, `affiliate_gmv`, `video_gmv`, `live_gmv`, `shop_tab_gmv`, `shop_tab_impressions`, `units_sold`, `subscription_gmv`, `new_subscriptions`, `active_subscriptions`, `recurring_subscriptions`"
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "ASC",
                      "DESC"
                    ],
                    "description": "`ASC` or `DESC`"
                  },
                  "product_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by product ID"
                  }
                }
              },
              "example": {
                "page_size": 10,
                "page_number": 1,
                "search_params": {
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-05-01"
                  },
                  "sort_by": "total_gmv",
                  "sort_direction": "DESC",
                  "product_id": "product_id_123"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "product_id": {
                            "type": "string"
                          },
                          "product_name": {
                            "type": "string"
                          },
                          "price": {
                            "type": "number"
                          },
                          "status": {
                            "type": "number"
                          },
                          "is_open_plan": {
                            "type": "boolean"
                          },
                          "total_gmv": {
                            "type": "number"
                          },
                          "affiliate_gmv": {
                            "type": "number"
                          },
                          "video_gmv": {
                            "type": "number"
                          },
                          "live_gmv": {
                            "type": "number"
                          },
                          "shop_tab_gmv": {
                            "type": "number"
                          },
                          "shop_tab_impressions": {
                            "type": "number"
                          },
                          "units_sold": {
                            "type": "number"
                          },
                          "subscription_gmv": {
                            "type": "number"
                          },
                          "new_subscriptions": {
                            "type": "number"
                          },
                          "active_subscriptions": {
                            "type": "number"
                          },
                          "recurring_subscriptions": {
                            "type": "number"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "total_count": {
                      "type": "integer"
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "product_id": "product_id_123",
                          "product_name": "Example Product Name",
                          "price": 30,
                          "status": 1,
                          "is_open_plan": true,
                          "total_gmv": 12345.67,
                          "affiliate_gmv": 8000,
                          "video_gmv": 7500,
                          "live_gmv": 500,
                          "shop_tab_gmv": 3845.67,
                          "shop_tab_impressions": 123456,
                          "units_sold": 410,
                          "subscription_gmv": 1820.5,
                          "new_subscriptions": 32,
                          "active_subscriptions": 148,
                          "recurring_subscriptions": 116
                        }
                      ],
                      "has_more": true,
                      "total_count": 14
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/timeseries/skus": {
      "post": {
        "operationId": "tsSkus",
        "summary": "SKU Timeseries Search",
        "description": "Search SKUs (product variants) by performance over a specific date range. Returns per-SKU GMV, units sold, orders and gross sales during the period, enriched with the SKU's name and price. Supports filtering by SKU or product.",
        "tags": [
          "Products"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ts-skus"
        },
        "security": [
          {
            "apiKey": [
              "POST /timeseries/skus"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "search_params": {
                    "type": "object",
                    "properties": {
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "product_id": {
                        "type": "string"
                      },
                      "sku_id": {
                        "type": "string"
                      }
                    }
                  },
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "Object with `from` and `to` dates (YYYY-MM-DD)"
                  },
                  "sort_by": {
                    "type": "string",
                    "enum": [
                      "gmv",
                      "units_sold",
                      "orders",
                      "gross_sales"
                    ],
                    "description": "One of `gmv`, `units_sold`, `orders`, `gross_sales`"
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "ASC",
                      "DESC"
                    ],
                    "description": "`ASC` or `DESC`"
                  },
                  "product_id": {
                    "type": "string",
                    "description": "*(optional)* Filter to a single product's SKUs"
                  },
                  "sku_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by SKU ID"
                  }
                }
              },
              "example": {
                "page_size": 10,
                "page_number": 1,
                "search_params": {
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-05-01"
                  },
                  "sort_by": "gmv",
                  "sort_direction": "DESC",
                  "product_id": "product_id_123",
                  "sku_id": "sku_id_123"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "sku_id": {
                            "type": "string"
                          },
                          "sku_name": {
                            "type": "string"
                          },
                          "product_id": {
                            "type": "string"
                          },
                          "product_name": {
                            "type": "string"
                          },
                          "price": {
                            "type": "number"
                          },
                          "gmv": {
                            "type": "number"
                          },
                          "units_sold": {
                            "type": "number"
                          },
                          "orders": {
                            "type": "number"
                          },
                          "gross_sales": {
                            "type": "number"
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "total_count": {
                      "type": "integer"
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "sku_id": "sku_id_123",
                          "sku_name": "Shade 01 – Ivory",
                          "product_id": "product_id_123",
                          "product_name": "Example Product Name",
                          "price": 30,
                          "gmv": 4820.5,
                          "units_sold": 161,
                          "orders": 154,
                          "gross_sales": 5106.9
                        }
                      ],
                      "has_more": true,
                      "total_count": 12
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/shop/stats": {
      "post": {
        "operationId": "stats",
        "summary": "Shop Stats",
        "description": "Retrieve aggregated shop analytics and performance metrics for a given date range. Optionally include daily breakdowns for charting.\n\n**Available stats:**\n\n- `affiliate_gmv`: Affiliate GMV driven by brand in time period\n- `total_gmv`: Total GMV including affiliate, ads, and organic\n- `affiliate_units_sold`: Affiliate units sold in time period\n- `total_units_sold`: Total units sold including affiliate, ads, and organic\n- `videos_posted`: All videos posted (affiliate + brand)\n- `affiliate_videos_posted`: Affiliate-only videos posted\n- `video_views`: Video views driven in time period\n- `likes`: Likes from affiliate videos\n- `comments`: Comments from affiliate videos\n- `gpm`: GMV per 1,000 views\n- `emv`: Earned media value = (views / 1000) × CPM\n- `commission`: Affiliate commission paid\n- `distinct_creators`: Unique creators who posted\n- `first_time_posters`: Affiliates who made their first ever post\n- `daily_active_affiliates`: Creators with sales — creators earning nonzero GMV. Unfiltered this is attribution-based (includes LIVE); with a `campaign_id`/`product_id` filter it counts video-attributed sales only\n- `dms_sent`: DMs sent from Cruva (includes open plan cards)\n- `open_plan_cards_sent`: Open plan cards sent from Cruva (subset of `dms_sent`)\n- `followup_dms_sent`: Followup DMs sent from Cruva (not included in `dms_sent`)\n- `replies`: Creator replies received\n- `tc_invites_sent`: Target Collaboration invites sent from Cruva\n- `sample_requests`: Sample requests received\n- `tc_sample_requests`: Sample requests via Target Collaboration (subset of `sample_requests`)\n- `open_sample_requests`: Sample requests via Open Collaboration (subset of `sample_requests`)\n- `samples_approved`: Samples approved\n- `samples_delivered`: Samples delivered\n- `gmv_per_sample_delivered`: GMV per sample delivered\n- `live_gmv`: LIVE stream GMV. Unfiltered requests use authoritative shop-wide totals; `campaign_id`/`product_id` filters only cover tracked lives\n- `lives_posted`: Number of LIVE streams\n- `slideshow_gmv`: GMV driven by shoppable slideshows (photo-mode posts). Tracked separately from `video_gmv` — the two do not overlap\n- `slideshow_posts`: Number of slideshows posted. Counted on the day each slideshow was published\n- `slideshow_views`: Views on shoppable slideshows during the period\n- `video_gmv`: GMV driven by short-form videos\n- `shop_tab_gmv`: GMV driven from the shop tab\n- `shop_tab_impressions`: Impressions on the shop tab\n- `ad_spend`: Total ad spend during the period\n- `ad_roi`: Return on ad spend (GMV / ad spend)\n- `refund_amount`: Total refunds (currency). Shop-wide — ignores `campaign_id`; `product_id` returns 0\n- `items_refunded`: Number of items refunded. Shop-wide — cannot be filtered by product or campaign: ignores `campaign_id`; `product_id` returns 0\n- `gmv_with_cofunding`: GMV including cofunding (currency). Shop-wide — ignores `campaign_id`; `product_id` returns 0\n- `platform_orders`: Total platform orders. Shop-wide — ignores `campaign_id`; `product_id` returns 0\n- `aov`: Average order value (currency). Total is the average across non-zero days, not a sum. Respects `product_id`\n- `new_content_gmv`: GMV from videos posted within the period (currency). Respects `campaign_id` and `product_id`\n- `emails_sent`: Emails sent from Cruva. Respects `campaign_id`\n- `samples_shipped`: Samples shipped. Respects `campaign_id`, `product_id`, and `only_show_campaign_stats`\n- `refundable_sample_requests`: Refundable samples requested (creator buys and is refunded after posting). Respects `campaign_id` and `product_id`\n- `refundable_samples_shipped`: Refundable samples shipped. Respects `campaign_id` and `product_id`\n- `refundable_samples_delivered`: Refundable samples delivered/received. Respects `campaign_id` and `product_id`\n- `samples_refunded`: Refundable samples refunded, bucketed by refund date. Respects `campaign_id` and `product_id`\n- `sample_refund_amount`: Total refund amount paid for refundable samples (currency), bucketed by refund date. Respects `campaign_id` and `product_id`\n- `customer_count`: Sum of daily shop-level customers; product-level customers when `product_id` is set. Repeat buyers across days can count more than once\n- `add_to_cart_count`: Add to cart events. Whole-shop sum unless `product_id` is set\n- `shipping_fees`: Shipping fees (currency). Whole-shop sum unless `product_id` is set\n- `product_impressions`: Product impressions. Whole-shop sum unless `product_id` is set\n- `subscription_revenue`: Revenue from subscription orders (currency). Ignores `campaign_id`; respects `product_id`\n- `one_time_purchase_gmv`: GMV from one-time, non-subscription purchases (currency). Shop-wide — ignores `campaign_id` and `product_id`\n- `recurrent_order_gmv`: GMV from repeat/recurring subscription orders (currency). Shop-wide — ignores `campaign_id` and `product_id`\n- `first_subscription_order_gmv`: GMV from the first order of each new subscription (currency). Shop-wide — ignores `campaign_id` and `product_id`\n- `non_recurring_gmv`: One-time purchase GMV plus first-subscription-order GMV — the GMV that is not a repeat subscription order (currency). Shop-wide — ignores `campaign_id` and `product_id`\n- `new_subscriptions`: Subscriptions started during the period. Ignores `campaign_id`; respects `product_id`\n- `active_subscribers`: Distinct active subscribers. **Point-in-time** — the value on the latest reported day, not a sum over the period; unreported days carry the previous level forward in `daily_counts`. Shop-wide — ignores `campaign_id` and `product_id`\n- `active_subscriptions`: Active subscriptions (a subscriber may hold several). **Point-in-time** — latest reported day, not a sum. Ignores `campaign_id`; respects `product_id`\n- `subscription_aov`: Average subscription order value (currency). Period value is total revenue / total orders, not an average of daily averages. Shop-wide — ignores `campaign_id` and `product_id`\n- `subscription_retention_rate`: Percent of subscriptions retained (0–100). Period value is weighted by each day's active subscriptions, never a flat average. Shop-wide — ignores `campaign_id` and `product_id`\n- `subscription_take_rate`: Percent of orders that are subscriptions (0–100). Period value is weighted by each day's subscription revenue. Shop-wide — ignores `campaign_id` and `product_id`\n- `avg_videos_per_creator`: Average videos posted per creator\n- `avg_gmv_per_video`: Average GMV per video\n- `sample_ratio`: Sample requests / Target Collabs sent\n- `reply_ratio`: Replies / DMs sent\n- `sample_post_rate`: Percent of samples delivered in the period that have been posted (0–100). Cohorted on delivery date, so a recent window reads low until creators post. Daily series is the same rate per delivery day\n\nStats marked **No** for Chart will return `total_count` and `percent_change` only, even if `include_charts` is true.\n\n**Subscription stats** come from the TikTok Shop seller subscription data, which has no campaign or product breakdown — so every subscription stat ignores `campaign_id`, and only `subscription_revenue`, `new_subscriptions`, and `active_subscriptions` respond to `product_id`. A day the shop reported nothing is skipped rather than counted as zero: in `daily_counts` the rate/AOV stats return `null` for those days (so a chart breaks the line instead of dipping to 0), and the two point-in-time counts carry the previous day's level forward. Because those two are point-in-time, their `daily_counts` will not sum to `total_count`.",
        "tags": [
          "Analytics"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#stats"
        },
        "security": [
          {
            "apiKey": [
              "POST /shop/stats"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Timezones.** By default you don't need to send anything: your numbers are already reported on the timezone your TikTok Shop is registered in, so the days line up with what you see in Seller Center.\n\nPass `timezone` when that isn't what you want — the boundaries look shifted, or you want to read the same period from another region's point of view. Give it an IANA name (`America/Los_Angeles`, `Europe/London`, `Asia/Singapore`); an unrecognised value returns `400` rather than being silently ignored.\n\nOne limit worth knowing: `timezone` re-cuts the days for events Cruva timestamps itself — DMs, replies, Target Collab invites, emails, videos posted, sample requests/approvals/shipments/deliveries, and lives. Metrics that arrive from TikTok already summarised per day — GMV, units sold, orders, commission, ad spend, shop-tab, AOV, refunds and every subscription metric — keep TikTok's own day boundaries, because a daily total can't be re-split after the fact. So on a mixed request the outreach and content stats move and the revenue stats don't. `date_range` is still read as plain calendar dates in the timezone you name, and the period-over-period comparison window shifts with it.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "Object with `from` and `to` dates (YYYY-MM-DD)"
                  },
                  "include_charts": {
                    "type": "boolean",
                    "description": "If `true`, includes `daily_counts` array for each stat"
                  },
                  "stats": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of stat keys to retrieve (see table below)"
                  },
                  "product_id": {
                    "type": "string",
                    "description": "*(optional)* Filter results to a specific product"
                  },
                  "cpm": {
                    "type": "number",
                    "description": "*(optional)* CPM value for earned media value calculation. Defaults to 5"
                  },
                  "timezone": {
                    "type": "string",
                    "description": "*(optional)* IANA timezone name (e.g. `America/Los_Angeles`) deciding which calendar day each event falls on. Omit unless the day boundaries look wrong — see **Timezones** below"
                  }
                }
              },
              "example": {
                "date_range": {
                  "from": "2026-03-01",
                  "to": "2026-04-01"
                },
                "include_charts": true,
                "stats": [
                  "affiliate_gmv",
                  "videos_posted",
                  "emv"
                ],
                "product_id": "1234567890",
                "cpm": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response (with charts)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "stats": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string"
                              },
                              "title": {
                                "type": "string"
                              },
                              "total_count": {
                                "type": "number"
                              },
                              "daily_counts": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "date": {
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "count": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "percent_change": {
                                "type": "number"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_with_charts": {
                    "summary": "Response (with charts)",
                    "value": {
                      "data": {
                        "stats": [
                          {
                            "key": "affiliate_gmv",
                            "title": "Affiliate GMV",
                            "total_count": 188444.1,
                            "daily_counts": [
                              {
                                "date": "2026-03-28",
                                "count": 37140
                              },
                              {
                                "date": "2026-03-29",
                                "count": 37791.58
                              },
                              {
                                "date": "2026-03-30",
                                "count": 37531.16
                              },
                              {
                                "date": "2026-03-31",
                                "count": 36756.52
                              },
                              {
                                "date": "2026-04-01",
                                "count": 39224.84
                              }
                            ],
                            "percent_change": -8.1
                          }
                        ]
                      }
                    }
                  },
                  "Response_without_charts": {
                    "summary": "Response (without charts)",
                    "value": {
                      "data": {
                        "stats": [
                          {
                            "key": "affiliate_gmv",
                            "title": "Affiliate GMV",
                            "total_count": 188444.1,
                            "percent_change": -8.1
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/shop/sps": {
      "get": {
        "operationId": "sps",
        "summary": "Shop Performance Score",
        "description": "Retrieve your shop's performance score. This is a measure of your shop's overall health on a scale of 0 to 5. If your score drops below 3.5, your shop will be restricted from sending messages to creators.",
        "tags": [
          "Shop health"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#sps"
        },
        "security": [
          {
            "apiKey": [
              "GET /shop/sps"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "sps": {
                          "type": "number"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "sps": 4.5
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/halo-effect": {
      "post": {
        "operationId": "haloEffectReport",
        "summary": "Halo Effect - Report",
        "description": "How your TikTok video views and TikTok Shop GMV line up with your Shopify and Amazon revenue over a date range. Returns the halo KPIs (views ↔ revenue correlation, estimated halo revenue, revenue per 1K views, off-TikTok $ per TikTok Shop $), TikTok totals, per-platform totals with campaign lift, and a chart-ready `series`.",
        "tags": [
          "Halo Effect"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#halo-effect-report"
        },
        "security": [
          {
            "apiKey": [
              "POST /halo-effect"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Also callable with `GET` and query parameters (`date_from`, `date_to`, …).\n\nAdd `\"format\": \"csv\"` to receive the `series` rows as a presigned CSV download link instead of inline JSON.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "Object with `from` and `to` dates (YYYY-MM-DD), both inclusive. At most **366 days**. `date_from` / `date_to` are accepted instead."
                  },
                  "tiktok_product_id": {
                    "type": "string",
                    "description": "*(optional)* Narrow the report to one TikTok product: TikTok numbers cover just that product, and platform numbers cover just the Shopify products/variants and Amazon ASINs it is linked to (see [Product Links](https://cruva.com/docs/api#halo-effect-product-links)). A platform the product isn't linked to comes back with `status: \"not_linked\"`."
                  },
                  "exclude_tiktok_gmv": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "boolean"
                      },
                      {
                        "type": "string"
                      }
                    ],
                    "description": "*(optional)* `true` for every platform, or a list (`[\"shopify\"]`, `\"amazon,shopify\"`). Subtracts each day's TikTok Shop GMV from that platform's revenue (floored at 0). Use it when TikTok Shop orders sync into your Shopify store or Amazon account and would otherwise be counted twice."
                  },
                  "granularity": {
                    "type": "string",
                    "description": "*(optional)* `day` (default), `week` (buckets start on Monday), or `month`. Only affects `series` — the halo stats always use daily data."
                  },
                  "include_top_videos": {
                    "type": "boolean",
                    "description": "*(optional)* If `true`, adds `top_videos_per_day`: the 4 most-viewed videos each day plus an `other` bucket for the rest."
                  },
                  "format": {
                    "type": "string",
                    "description": "*(optional)* `csv` for a presigned CSV download of `series`."
                  }
                }
              },
              "example": {
                "date_range": {
                  "from": "2026-09-01",
                  "to": "2026-09-28"
                },
                "tiktok_product_id": "1729000000000000001",
                "exclude_tiktok_gmv": [
                  "shopify"
                ],
                "granularity": "day",
                "include_top_videos": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "date_from": {
                          "type": "string",
                          "format": "date"
                        },
                        "date_to": {
                          "type": "string",
                          "format": "date"
                        },
                        "granularity": {
                          "type": "string"
                        },
                        "tiktok_product_id": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "tiktok_product_name": {},
                        "halo": {
                          "type": "object",
                          "properties": {
                            "correlation": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "Pearson correlation (0–1) between daily TikTok views and daily off-TikTok revenue (Shopify + Amazon). Floored at 0 — a halo can't be negative. `null` with fewer than 3 active days."
                            },
                            "est_halo_revenue": {
                              "type": "number",
                              "description": "Estimated off-TikTok revenue attributable to TikTok views: the regression slope (revenue per view) × total views. `0` when the slope isn't positive."
                            },
                            "revenue_per_1k_views": {
                              "type": "number",
                              "description": "Off-TikTok revenue per 1,000 TikTok views."
                            },
                            "multiplier": {
                              "type": [
                                "number",
                                "null"
                              ],
                              "description": "Off-TikTok revenue per $1 of TikTok Shop GMV. `null` when there is no TikTok Shop GMV."
                            },
                            "total_views": {
                              "type": "number"
                            },
                            "total_off_platform_revenue": {
                              "type": "number"
                            },
                            "total_tiktok_gmv": {
                              "type": "number"
                            },
                            "sample_size": {
                              "type": "number",
                              "description": "Days with views or off-TikTok revenue that the stats were computed over."
                            }
                          }
                        },
                        "tiktok": {
                          "type": "object",
                          "properties": {
                            "gmv": {
                              "type": "number"
                            },
                            "views": {
                              "type": "number"
                            },
                            "gmv_source": {
                              "type": "string",
                              "description": "`shop_performance.platform_gmv` (whole TikTok Shop GMV, not just affiliate videos) shop-wide; `daily_product_stats.total_gmv` when `tiktok_product_id` is set."
                            }
                          }
                        },
                        "platforms": {
                          "type": "object",
                          "properties": {
                            "shopify": {
                              "type": "object",
                              "properties": {
                                "connected": {
                                  "type": "boolean"
                                },
                                "linked_product_count": {
                                  "type": "integer",
                                  "description": "Number of product links on the platform; when `tiktok_product_id` is set, the matching link rows instead."
                                },
                                "status": {
                                  "type": "string",
                                  "description": "`ok`, `refreshing` (Shopify snapshot being built — retry shortly), `not_linked` (the selected product isn't linked on this platform), or `error` (the platform's data is unavailable right now; the rest of the report still returns). Absent when `connected` is `false`."
                                },
                                "snapshot_from": {
                                  "type": "string",
                                  "format": "date",
                                  "description": "Dates the Shopify snapshot covers and when it was last refreshed."
                                },
                                "snapshot_to": {
                                  "type": "string",
                                  "format": "date",
                                  "description": "Dates the Shopify snapshot covers and when it was last refreshed."
                                },
                                "refreshed_at": {
                                  "type": "string",
                                  "format": "date-time",
                                  "description": "Dates the Shopify snapshot covers and when it was last refreshed."
                                },
                                "totals": {
                                  "type": "object",
                                  "properties": {
                                    "revenue": {
                                      "type": "number"
                                    },
                                    "orders": {
                                      "type": "number"
                                    },
                                    "units": {
                                      "type": "number"
                                    },
                                    "aov": {
                                      "type": "number"
                                    },
                                    "revenue_change_pct": {
                                      "type": "number"
                                    },
                                    "orders_change_pct": {
                                      "type": "number"
                                    },
                                    "units_change_pct": {
                                      "type": "number"
                                    }
                                  },
                                  "description": "Revenue, orders, units, and AOV over the range. `*_change_pct` compares the average day in the second half of the range to the first half — not a prior-period comparison. Not netted by `exclude_tiktok_gmv`."
                                },
                                "campaign_impact": {
                                  "type": [
                                    "array",
                                    "null"
                                  ],
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "campaign_id": {
                                        "type": "string"
                                      },
                                      "campaign_name": {
                                        "type": "string"
                                      },
                                      "campaign_type": {
                                        "type": "string"
                                      },
                                      "start_date": {
                                        "type": "string",
                                        "format": "date-time"
                                      },
                                      "end_date": {
                                        "type": "string",
                                        "format": "date-time"
                                      },
                                      "lift_pct": {
                                        "type": [
                                          "number",
                                          "null"
                                        ]
                                      },
                                      "baseline_daily_revenue": {
                                        "type": [
                                          "number",
                                          "null"
                                        ]
                                      },
                                      "baseline_complete": {
                                        "type": [
                                          "boolean",
                                          "null"
                                        ]
                                      },
                                      "campaign_revenue": {
                                        "type": "number"
                                      },
                                      "days_active": {
                                        "type": "number"
                                      }
                                    }
                                  },
                                  "description": "Per Cruva campaign overlapping the range: `lift_pct` compares average daily revenue during the campaign to the 14 days before it. When that baseline reaches before the platform's data, `lift_pct` and `baseline_daily_revenue` are `null` and `baseline_complete` is `false`."
                                },
                                "net_of_tiktok_gmv": {
                                  "type": "boolean"
                                },
                                "halo_revenue": {
                                  "type": "number",
                                  "description": "The platform's revenue over the range as used in the halo stats — netted of TikTok Shop GMV when `net_of_tiktok_gmv` is `true`."
                                },
                                "store": {
                                  "type": "string"
                                },
                                "refresh_started_at": {
                                  "type": "string",
                                  "format": "date-time"
                                }
                              }
                            },
                            "amazon": {
                              "type": "object",
                              "properties": {
                                "connected": {
                                  "type": "boolean"
                                },
                                "linked_product_count": {
                                  "type": "integer",
                                  "description": "Number of product links on the platform; when `tiktok_product_id` is set, the matching link rows instead."
                                },
                                "status": {
                                  "type": "string",
                                  "description": "`ok`, `refreshing` (Shopify snapshot being built — retry shortly), `not_linked` (the selected product isn't linked on this platform), or `error` (the platform's data is unavailable right now; the rest of the report still returns). Absent when `connected` is `false`."
                                },
                                "auth_error": {
                                  "type": "boolean",
                                  "description": "`true` when the Amazon authorization has expired or been revoked — reconnect Amazon in the dashboard."
                                },
                                "totals": {
                                  "type": "object",
                                  "properties": {
                                    "revenue": {
                                      "type": "number"
                                    },
                                    "orders": {
                                      "type": "number"
                                    },
                                    "units": {
                                      "type": "number"
                                    },
                                    "aov": {
                                      "type": "number"
                                    },
                                    "revenue_change_pct": {
                                      "type": "number"
                                    },
                                    "orders_change_pct": {
                                      "type": "number"
                                    },
                                    "units_change_pct": {
                                      "type": "number"
                                    }
                                  },
                                  "description": "Revenue, orders, units, and AOV over the range. `*_change_pct` compares the average day in the second half of the range to the first half — not a prior-period comparison. Not netted by `exclude_tiktok_gmv`."
                                },
                                "campaign_impact": {
                                  "type": [
                                    "array",
                                    "null"
                                  ],
                                  "items": {},
                                  "description": "Per Cruva campaign overlapping the range: `lift_pct` compares average daily revenue during the campaign to the 14 days before it. When that baseline reaches before the platform's data, `lift_pct` and `baseline_daily_revenue` are `null` and `baseline_complete` is `false`."
                                },
                                "net_of_tiktok_gmv": {
                                  "type": "boolean"
                                },
                                "halo_revenue": {
                                  "type": "number",
                                  "description": "The platform's revenue over the range as used in the halo stats — netted of TikTok Shop GMV when `net_of_tiktok_gmv` is `true`."
                                },
                                "account_type": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        },
                        "series": {
                          "type": [
                            "array",
                            "null"
                          ],
                          "items": {
                            "type": "object",
                            "properties": {
                              "date": {
                                "type": "string",
                                "format": "date"
                              },
                              "tiktok_views": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              },
                              "tiktok_gmv": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              },
                              "shopify_revenue": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              },
                              "amazon_revenue": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              },
                              "off_platform_revenue": {
                                "type": [
                                  "number",
                                  "null"
                                ]
                              }
                            }
                          },
                          "description": "One row per day (or week/month) with `tiktok_views`, `tiktok_gmv`, `shopify_revenue`, `amazon_revenue`, and `off_platform_revenue`. A platform's revenue is `null` on days it has no data; `off_platform_revenue` is `null` when any reporting platform is. With `week`/`month`, a platform that doesn't cover the whole period is `null` for that period rather than a partial sum."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "date_from": "2026-09-01",
                        "date_to": "2026-09-28",
                        "granularity": "day",
                        "tiktok_product_id": null,
                        "tiktok_product_name": null,
                        "halo": {
                          "correlation": 0.6132,
                          "est_halo_revenue": 18420.55,
                          "revenue_per_1k_views": 12.84,
                          "multiplier": 0.4211,
                          "total_views": 2481903,
                          "total_off_platform_revenue": 31866.12,
                          "total_tiktok_gmv": 75674.3,
                          "sample_size": 28
                        },
                        "tiktok": {
                          "gmv": 75674.3,
                          "views": 2481903,
                          "gmv_source": "shop_performance.platform_gmv"
                        },
                        "platforms": {
                          "shopify": {
                            "connected": true,
                            "linked_product_count": 6,
                            "status": "ok",
                            "snapshot_from": "2026-03-01",
                            "snapshot_to": "2026-09-29",
                            "refreshed_at": "2026-09-29T07:12:44+00:00",
                            "totals": {
                              "revenue": 24210.4,
                              "orders": 412,
                              "units": 530,
                              "aov": 58.76,
                              "revenue_change_pct": 14.2,
                              "orders_change_pct": 11.8,
                              "units_change_pct": 12.5
                            },
                            "campaign_impact": [
                              {
                                "campaign_id": "66f1c2a9e4b0a1d2c3f4e5a6",
                                "campaign_name": "September Creator Push",
                                "campaign_type": "retainer",
                                "start_date": "2026-09-10T00:00:00+00:00",
                                "end_date": "2026-09-24T00:00:00+00:00",
                                "lift_pct": 22.4,
                                "baseline_daily_revenue": 745.1,
                                "baseline_complete": true,
                                "campaign_revenue": 13690.33,
                                "days_active": 15
                              }
                            ],
                            "net_of_tiktok_gmv": false,
                            "halo_revenue": 24210.4,
                            "store": "acme.myshopify.com"
                          },
                          "amazon": {
                            "connected": true,
                            "linked_product_count": 2,
                            "status": "ok",
                            "auth_error": false,
                            "totals": {
                              "revenue": 7655.72,
                              "orders": 131,
                              "units": 158,
                              "aov": 58.44,
                              "revenue_change_pct": 6.1,
                              "orders_change_pct": 4.9,
                              "units_change_pct": 5.3
                            },
                            "campaign_impact": [],
                            "net_of_tiktok_gmv": false,
                            "halo_revenue": 7655.72,
                            "account_type": "seller"
                          }
                        },
                        "series": [
                          {
                            "date": "2026-09-01",
                            "tiktok_views": 81220,
                            "tiktok_gmv": 2410.5,
                            "shopify_revenue": 812.4,
                            "amazon_revenue": 240.1,
                            "off_platform_revenue": 1052.5
                          }
                        ]
                      }
                    }
                  },
                  "Response_Shopify_snapshot_still_building": {
                    "summary": "Response (Shopify snapshot still building)",
                    "value": {
                      "data": {
                        "platforms": {
                          "shopify": {
                            "connected": true,
                            "linked_product_count": 6,
                            "status": "refreshing",
                            "refresh_started_at": "2026-09-30T15:02:11+00:00",
                            "store": "acme.myshopify.com"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/halo-effect/product-links": {
      "post": {
        "operationId": "haloEffectProductLinks",
        "summary": "Halo Effect - Product Links",
        "description": "List the Shopify and Amazon connections used by the halo effect and every TikTok product link on them. Use a row's `tiktok_product_id` as the `tiktok_product_id` of [Halo Effect - Report](https://cruva.com/docs/api#halo-effect-report) to narrow the report to that product. Links are created and removed in the dashboard (Content → Halo Effect); this endpoint only reads them.",
        "tags": [
          "Halo Effect"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#halo-effect-product-links"
        },
        "security": [
          {
            "apiKey": [
              "POST /halo-effect/product-links"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "All fields are optional — send an empty body for every link. Also callable with `GET` and query parameters.\n\nAdd `\"format\": \"csv\"` to receive the `product_links` rows as a presigned CSV download link.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tiktok_product_id": {
                    "type": "string",
                    "description": "*(optional)* Only this TikTok product's links."
                  },
                  "platform": {
                    "type": "string",
                    "description": "*(optional)* `shopify` or `amazon`."
                  },
                  "format": {
                    "type": "string",
                    "description": "*(optional)* `csv` for a presigned CSV download of `product_links`."
                  }
                }
              },
              "example": {
                "tiktok_product_id": "1729000000000000001",
                "platform": "shopify"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "connections": {
                          "type": "object",
                          "properties": {
                            "shopify": {
                              "type": "object",
                              "properties": {
                                "connected": {
                                  "type": "boolean"
                                },
                                "is_active": {
                                  "type": "boolean"
                                },
                                "store": {
                                  "type": "string"
                                },
                                "store_name": {
                                  "type": "string"
                                },
                                "owns_connection": {
                                  "type": "boolean",
                                  "description": "`false` when this shop uses a Shopify store connected by another of your shops (e.g. one store serving several regional shops)."
                                },
                                "last_sync_at": {
                                  "type": "string"
                                }
                              }
                            },
                            "amazon": {
                              "type": "object",
                              "properties": {
                                "connected": {
                                  "type": "boolean"
                                },
                                "is_active": {
                                  "type": "boolean"
                                },
                                "account_type": {
                                  "type": "string"
                                },
                                "marketplace_id": {
                                  "type": "string"
                                },
                                "region": {
                                  "type": "string"
                                },
                                "needs_reauth": {
                                  "type": "boolean",
                                  "description": "`true` when the Amazon authorization has expired — reconnect Amazon in the dashboard."
                                },
                                "last_sync_at": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        },
                        "tiktok_products": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "tiktok_product_id": {
                                "type": "string"
                              },
                              "tiktok_product_name": {
                                "type": "string"
                              },
                              "shopify_links": {
                                "type": "number"
                              },
                              "amazon_links": {
                                "type": "number"
                              }
                            }
                          },
                          "description": "Each linked TikTok product with its number of Shopify and Amazon links."
                        },
                        "product_links": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "platform": {
                                "type": "string"
                              },
                              "tiktok_product_id": {
                                "type": "string"
                              },
                              "tiktok_product_name": {
                                "type": "string"
                              },
                              "shopify_product_id": {
                                "type": "string"
                              },
                              "shopify_variant_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "shopify_product_name": {
                                "type": "string"
                              },
                              "grain": {
                                "type": "string",
                                "description": "Shopify only: `product` (all variants) or `variant` (just `shopify_variant_id`)."
                              },
                              "linked_at": {
                                "type": "string"
                              },
                              "amazon_asin": {
                                "type": "string"
                              },
                              "amazon_product_name": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "connections": {
                          "shopify": {
                            "connected": true,
                            "is_active": true,
                            "store": "acme.myshopify.com",
                            "store_name": "Acme",
                            "owns_connection": true,
                            "last_sync_at": "2026-09-29T07:12:44"
                          },
                          "amazon": {
                            "connected": true,
                            "is_active": true,
                            "account_type": "seller",
                            "marketplace_id": "ATVPDKIKX0DER",
                            "region": "us",
                            "needs_reauth": false,
                            "last_sync_at": "2026-09-30T09:40:02"
                          }
                        },
                        "tiktok_products": [
                          {
                            "tiktok_product_id": "1729000000000000001",
                            "tiktok_product_name": "Cloud Pillow",
                            "shopify_links": 2,
                            "amazon_links": 1
                          }
                        ],
                        "product_links": [
                          {
                            "id": "66f1c2a9e4b0a1d2c3f4e5b1",
                            "platform": "shopify",
                            "tiktok_product_id": "1729000000000000001",
                            "tiktok_product_name": "Cloud Pillow",
                            "shopify_product_id": "8123456789012",
                            "shopify_variant_id": null,
                            "shopify_product_name": "Cloud Pillow",
                            "grain": "product",
                            "linked_at": "2026-08-14T18:22:05"
                          },
                          {
                            "id": "66f1c2a9e4b0a1d2c3f4e5b3",
                            "platform": "amazon",
                            "tiktok_product_id": "1729000000000000001",
                            "tiktok_product_name": "Cloud Pillow",
                            "amazon_asin": "B0C1234567",
                            "amazon_product_name": "Cloud Pillow, Queen",
                            "linked_at": "2026-08-14T18:25:41"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/crm/list": {
      "post": {
        "operationId": "crm",
        "summary": "CRM Search",
        "description": "Retrieve affiliates who have worked with your store (videos, sample requests, showcases).",
        "tags": [
          "CRM & Content"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#crm"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/crm/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer"
                  },
                  "page_number": {
                    "type": "integer"
                  },
                  "sort_by": {
                    "type": "string"
                  },
                  "sort_direction": {
                    "type": "string"
                  },
                  "just_count": {
                    "type": "boolean",
                    "description": "if true, returns only total_count (no results)"
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "handle": {
                        "type": "string"
                      },
                      "min_videos": {
                        "type": "number"
                      },
                      "affiliate_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number",
                            "description": "platform-wide 30-day GMV"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_followers": {
                            "type": "number"
                          },
                          "max_followers": {
                            "type": "number"
                          }
                        }
                      },
                      "shop_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number",
                            "description": "shop-specific lifetime GMV"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_video_gmv": {
                            "type": "number"
                          },
                          "max_video_gmv": {
                            "type": "number"
                          },
                          "min_live_gmv": {
                            "type": "number"
                          },
                          "max_live_gmv": {
                            "type": "number"
                          },
                          "min_units_sold": {
                            "type": "number"
                          },
                          "max_units_sold": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "page_size": 20,
                "page_number": 1,
                "sort_by": "gmv",
                "sort_direction": "desc",
                "just_count": false,
                "filters": {
                  "handle": "example_creator",
                  "min_videos": 0,
                  "affiliate_performance": {
                    "min_gmv": 1000,
                    "max_gmv": 100000,
                    "min_followers": 5000,
                    "max_followers": 500000
                  },
                  "shop_performance": {
                    "min_gmv": 0,
                    "max_gmv": 100000,
                    "min_video_gmv": 0,
                    "max_video_gmv": 100000,
                    "min_live_gmv": 0,
                    "max_live_gmv": 100000,
                    "min_units_sold": 0,
                    "max_units_sold": 10000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "shop_id": {
                            "type": "string"
                          },
                          "handle": {
                            "type": "string"
                          },
                          "creator_id": {
                            "type": "string"
                          },
                          "nickname": {
                            "type": "string"
                          },
                          "showcasing": {
                            "type": "boolean"
                          },
                          "units_sold": {
                            "type": "number",
                            "description": "What the creator earned for **your shop**, all-time (or within `date_range` when supplied)."
                          },
                          "video_count": {
                            "type": "integer",
                            "description": "What the creator earned for **your shop**, all-time (or within `date_range` when supplied)."
                          },
                          "gmv": {
                            "type": "number",
                            "description": "What the creator earned for **your shop**, all-time (or within `date_range` when supplied)."
                          },
                          "last_post": {
                            "description": "Most recent video post date, most recent LIVE date, and LIVE minutes for your shop."
                          },
                          "email": {
                            "description": "Contact details when known; `email` falls back to the creator's public profile email."
                          },
                          "phone_number": {
                            "description": "Contact details when known; `email` falls back to the creator's public profile email."
                          },
                          "video_gmv": {
                            "type": "number",
                            "description": "What the creator earned for **your shop**, all-time (or within `date_range` when supplied)."
                          },
                          "live_gmv": {
                            "type": "number",
                            "description": "What the creator earned for **your shop**, all-time (or within `date_range` when supplied)."
                          },
                          "live_count": {
                            "type": "integer",
                            "description": "What the creator earned for **your shop**, all-time (or within `date_range` when supplied)."
                          },
                          "commission": {
                            "type": "number",
                            "description": "What the creator earned for **your shop**, all-time (or within `date_range` when supplied)."
                          },
                          "last_live": {
                            "description": "Most recent video post date, most recent LIVE date, and LIVE minutes for your shop."
                          },
                          "live_duration": {
                            "type": "number",
                            "description": "Most recent video post date, most recent LIVE date, and LIVE minutes for your shop."
                          },
                          "med_gmv_revenue": {
                            "type": "number",
                            "description": "Platform-wide creator profile (not scoped to your shop): 30-day GMV across all brands, followers, number of brands worked with, posting rate, engagement rate and 30-day average views, as TikTok reports them."
                          },
                          "follower_cnt": {
                            "type": "integer",
                            "description": "Platform-wide creator profile (not scoped to your shop): 30-day GMV across all brands, followers, number of brands worked with, posting rate, engagement rate and 30-day average views, as TikTok reports them."
                          },
                          "brand_collaborations": {
                            "type": "number",
                            "description": "Platform-wide creator profile (not scoped to your shop): 30-day GMV across all brands, followers, number of brands worked with, posting rate, engagement rate and 30-day average views, as TikTok reports them."
                          },
                          "post_rate": {
                            "type": "number",
                            "description": "Platform-wide creator profile (not scoped to your shop): 30-day GMV across all brands, followers, number of brands worked with, posting rate, engagement rate and 30-day average views, as TikTok reports them."
                          },
                          "video_engagement": {
                            "type": "number",
                            "description": "Platform-wide creator profile (not scoped to your shop): 30-day GMV across all brands, followers, number of brands worked with, posting rate, engagement rate and 30-day average views, as TikTok reports them."
                          },
                          "category": {
                            "type": "string",
                            "description": "Content category, share of content per category (0–1), and top viewer regions."
                          },
                          "category_splits": {
                            "type": "object",
                            "properties": {
                              "Beauty & Personal Care": {
                                "type": "number"
                              },
                              "Health": {
                                "type": "number"
                              }
                            },
                            "description": "Content category, share of content per category (0–1), and top viewer regions."
                          },
                          "regional_geography": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "Content category, share of content per category (0–1), and top viewer regions."
                          },
                          "gender": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Creator attributes inferred from content; `null` when unknown."
                          },
                          "age": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Creator attributes inferred from content; `null` when unknown."
                          },
                          "race": {
                            "description": "Creator attributes inferred from content; `null` when unknown."
                          },
                          "body_type": {
                            "description": "Creator attributes inferred from content; `null` when unknown."
                          },
                          "economic_status": {
                            "description": "Creator attributes inferred from content; `null` when unknown."
                          },
                          "top_follower_gender": {
                            "type": "string",
                            "description": "Dominant audience gender and age band."
                          },
                          "top_follower_ages": {
                            "type": "string",
                            "description": "Dominant audience gender and age band."
                          },
                          "bio": {
                            "type": "string",
                            "description": "Creator's TikTok bio."
                          },
                          "tags": {
                            "type": "array",
                            "items": {},
                            "description": "Your shop's tags on this creator (see Tags)."
                          }
                        }
                      }
                    },
                    "has_more": {
                      "type": "boolean"
                    },
                    "page_size": {
                      "type": "integer"
                    },
                    "page_offset": {
                      "type": "number"
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "results": [
                        {
                          "shop_id": "your_shop_id_here",
                          "handle": "example_creator",
                          "creator_id": "7171717171717171717",
                          "nickname": "Example Creator",
                          "showcasing": true,
                          "units_sold": 9081,
                          "video_count": 80,
                          "gmv": 271487.8,
                          "last_post": null,
                          "email": null,
                          "phone_number": null,
                          "video_gmv": 271447.81,
                          "live_gmv": 0,
                          "live_count": 0,
                          "commission": 1234.5,
                          "last_live": null,
                          "live_duration": 0,
                          "med_gmv_revenue": 107199,
                          "follower_cnt": 84227,
                          "brand_collaborations": 12,
                          "post_rate": 1293,
                          "video_engagement": 4.2,
                          "category": "Beauty & Personal Care",
                          "category_splits": {
                            "Beauty & Personal Care": 0.71,
                            "Health": 0.29
                          },
                          "regional_geography": [
                            "US-CA",
                            "US-TX"
                          ],
                          "gender": "female",
                          "age": "25-34",
                          "race": null,
                          "body_type": null,
                          "economic_status": null,
                          "top_follower_gender": "female",
                          "top_follower_ages": "18-24",
                          "bio": "Skincare + wellness. DM for collabs",
                          "tags": []
                        }
                      ],
                      "has_more": false,
                      "page_size": 20,
                      "page_offset": 0
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/videos/list": {
      "post": {
        "operationId": "videos",
        "summary": "Videos Search",
        "description": "Retrieve videos and performance metrics.",
        "tags": [
          "CRM & Content"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#videos"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/videos/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer"
                  },
                  "page_number": {
                    "type": "integer"
                  },
                  "just_count": {
                    "type": "boolean",
                    "description": "if true, returns only total_count (no results)"
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "handle": {
                        "type": "string"
                      },
                      "product_filter": {
                        "type": "string"
                      },
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "affiliate_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number",
                            "description": "platform-wide 30-day GMV"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_followers": {
                            "type": "number"
                          },
                          "max_followers": {
                            "type": "number"
                          }
                        }
                      },
                      "shop_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number",
                            "description": "shop-specific lifetime GMV"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_video_gmv": {
                            "type": "number"
                          },
                          "max_video_gmv": {
                            "type": "number"
                          },
                          "min_live_gmv": {
                            "type": "number"
                          },
                          "max_live_gmv": {
                            "type": "number"
                          },
                          "min_units_sold": {
                            "type": "number"
                          },
                          "max_units_sold": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "page_size": 20,
                "page_number": 1,
                "just_count": false,
                "filters": {
                  "sort_by": "gmv",
                  "sort_direction": "desc",
                  "handle": "example_creator",
                  "product_filter": "product_id_123",
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "affiliate_performance": {
                    "min_gmv": 100,
                    "max_gmv": 100000,
                    "min_followers": 1000,
                    "max_followers": 500000
                  },
                  "shop_performance": {
                    "min_gmv": 0,
                    "max_gmv": 100000,
                    "min_video_gmv": 0,
                    "max_video_gmv": 100000,
                    "min_live_gmv": 0,
                    "max_live_gmv": 100000,
                    "min_units_sold": 0,
                    "max_units_sold": 10000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "shop_id": {
                                "type": "string"
                              },
                              "video_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "post_time": {
                                "type": "string"
                              },
                              "view_count": {
                                "type": "integer"
                              },
                              "units_sold": {
                                "type": "number"
                              },
                              "ctr": {
                                "type": "number"
                              },
                              "like_count": {
                                "type": "integer"
                              },
                              "comment_count": {
                                "type": "integer"
                              },
                              "title": {
                                "type": "string"
                              },
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "products": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "product": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "page_offset": {
                          "type": "number"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "shop_id": "your_shop_id_here",
                            "video_id": "12345678",
                            "handle": "example_creator",
                            "gmv": 130931.64,
                            "post_time": "02/26/2025",
                            "view_count": 3417702,
                            "units_sold": 3419,
                            "ctr": 1.6,
                            "like_count": 6382,
                            "comment_count": 169,
                            "title": "4 for 1 deal ends soon!",
                            "campaign_id": null,
                            "products": [
                              "product_id_123"
                            ],
                            "product": "product_id_123"
                          }
                        ],
                        "has_more": false,
                        "page_size": 20,
                        "page_offset": 0
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/timeseries/affiliates": {
      "post": {
        "operationId": "tsAffiliates",
        "summary": "CRM Timeseries Search",
        "description": "Search affiliates by performance over a specific date range — the windowed counterpart to **CRM Search**. Returns GMV (broken out by video, new-video and LIVE), commission, views, engagement metrics and more earned for your brand during the period. Supports sorting and filtering by handle.",
        "tags": [
          "CRM & Content"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ts-affiliates"
        },
        "security": [
          {
            "apiKey": [
              "POST /timeseries/affiliates"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "search_params": {
                    "type": "object",
                    "properties": {
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "handle": {
                        "type": "string"
                      }
                    }
                  },
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "Object with `from` and `to` dates (YYYY-MM-DD)"
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "Field to sort by: `gmv`, `video_gmv`, `new_video_gmv`, `commission`, `units_sold`, `video_count`, `live_count`, `views`, `likes`, `comments`. `live_gmv` is **not** sortable — see the response field notes below."
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "ASC",
                      "DESC"
                    ],
                    "description": "`ASC` or `DESC`"
                  },
                  "handle": {
                    "type": "string",
                    "description": "*(optional)* Filter by creator handle"
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by campaign"
                  },
                  "product_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by product ID"
                  }
                }
              },
              "example": {
                "page_size": 10,
                "page_number": 1,
                "search_params": {
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "sort_by": "gmv",
                  "sort_direction": "DESC",
                  "handle": "example_creator"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "handle": {
                            "type": "string"
                          },
                          "nickname": {
                            "type": "string"
                          },
                          "gmv": {
                            "type": "number",
                            "description": "Total shop GMV the creator drove in the window, across every channel (video, LIVE, showcase and other attributed sales). This is the total — `video_gmv` and `live_gmv` are subsets of it, and they do not necessarily add up to it."
                          },
                          "video_gmv": {
                            "type": "number",
                            "description": "GMV in the window attributed to the creator's videos, regardless of when each video was posted — so a video posted last year that still sells counts here. Clamped to `gmv`."
                          },
                          "new_video_gmv": {
                            "type": "number",
                            "description": "The subset of `video_gmv` earned by videos **posted inside the same `date_range`** — i.e. GMV from fresh content, not the back catalogue. With no `date_range` supplied there is nothing to scope by and this equals `video_gmv`. Clamped to `gmv`."
                          },
                          "live_gmv": {
                            "type": "number",
                            "description": "GMV in the window from the creator's LIVE streams, taken from LIVE session data (the same source as the LIVE endpoints) rather than the daily video stats. Because it is joined on after ranking, it cannot be used as a `sort_by` field."
                          },
                          "commission": {
                            "type": "number"
                          },
                          "views": {
                            "type": "number"
                          },
                          "likes": {
                            "type": "number"
                          },
                          "comments": {
                            "type": "number"
                          },
                          "units_sold": {
                            "type": "number"
                          },
                          "video_count": {
                            "type": "integer",
                            "description": "Videos the creator posted for your shop in the window."
                          },
                          "live_count": {
                            "type": "integer",
                            "description": "LIVE streams the creator ran for your shop in the window."
                          },
                          "engagement_rate": {
                            "type": "number",
                            "description": "`(likes + comments) / views`, as a percentage."
                          },
                          "conversion_rate": {
                            "type": "number",
                            "description": "`units_sold / views`, as a percentage."
                          },
                          "avg_gmv_per_view": {
                            "type": "number",
                            "description": "`gmv / views`."
                          },
                          "avg_order_value": {
                            "type": "number",
                            "description": "`gmv / units_sold`."
                          },
                          "creator_oecuid": {
                            "type": "string",
                            "description": "Stable TikTok creator id — survives handle changes; join on this, not `handle`."
                          },
                          "follower_cnt": {
                            "type": "integer",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "video_avg_view_cnt": {
                            "type": "integer",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "video_engagement": {
                            "type": "number",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "med_gmv_revenue": {
                            "type": "number",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "post_rate": {
                            "type": "number",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "category": {
                            "type": "string",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "top_follower_gender": {
                            "type": "string"
                          },
                          "top_follower_ages": {
                            "type": "string"
                          },
                          "gender": {
                            "type": "string",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "age": {
                            "type": "string",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          },
                          "bio": {
                            "type": "string",
                            "description": "Platform-wide creator profile as TikTok reports it — **not** scoped to your shop or to `date_range`. `video_avg_view_cnt` is TikTok's trailing-30-day average views per video; `0` means TikTok returned no value. Also present: `is_fast_growing`, `units_sold_range`, `med_gmv_revenue_range`, `race`, `body_type`, `economic_status`, `face_visibility`, `tone`, `language`, `tags`."
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "handle": "example_creator",
                          "nickname": "Example Creator",
                          "gmv": 4360.58,
                          "video_gmv": 4218.3,
                          "new_video_gmv": 1902.44,
                          "live_gmv": 142.28,
                          "commission": 186.88,
                          "views": 554296,
                          "likes": 4070,
                          "comments": 50,
                          "units_sold": 167,
                          "video_count": 10,
                          "live_count": 1,
                          "engagement_rate": 0.74,
                          "conversion_rate": 0.0301,
                          "avg_gmv_per_view": 0.0079,
                          "avg_order_value": 26.11,
                          "creator_oecuid": "7171717171717171717",
                          "follower_cnt": 84227,
                          "video_avg_view_cnt": 12840,
                          "video_engagement": 4.2,
                          "med_gmv_revenue": 107199,
                          "post_rate": 1293,
                          "category": "Beauty & Personal Care",
                          "top_follower_gender": "female",
                          "top_follower_ages": "18-24",
                          "gender": "female",
                          "age": "25-34",
                          "bio": "Skincare + wellness. DM for collabs"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/timeseries/videos": {
      "post": {
        "operationId": "tsVideos",
        "summary": "Video Timeseries Search",
        "description": "Search videos by performance over a specific date range — the windowed counterpart to **Videos Search**. Returns per-video GMV, views, engagement and conversion metrics earned during the period. Supports filtering by handle and product.",
        "tags": [
          "CRM & Content"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ts-videos"
        },
        "security": [
          {
            "apiKey": [
              "POST /timeseries/videos"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "search_params": {
                    "type": "object",
                    "properties": {
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "handle": {
                        "type": "string"
                      },
                      "product_id": {
                        "type": "string"
                      }
                    }
                  },
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "Object with `from` and `to` dates (YYYY-MM-DD)"
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "Field to sort by (e.g. `gmv`, `views`, `units_sold`)"
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "ASC",
                      "DESC"
                    ],
                    "description": "`ASC` or `DESC`"
                  },
                  "handle": {
                    "type": "string",
                    "description": "*(optional)* Filter by creator handle"
                  },
                  "product_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by product ID"
                  }
                }
              },
              "example": {
                "page_size": 10,
                "page_number": 1,
                "search_params": {
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "sort_by": "gmv",
                  "sort_direction": "DESC",
                  "handle": "example_creator",
                  "product_id": "product_id_123"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "video_id": {
                            "type": "string"
                          },
                          "handle": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "post_time": {
                            "type": "string"
                          },
                          "product_id": {
                            "type": "string"
                          },
                          "gmv": {
                            "type": "number"
                          },
                          "commission": {
                            "type": "number"
                          },
                          "views": {
                            "type": "number"
                          },
                          "likes": {
                            "type": "number"
                          },
                          "comments": {
                            "type": "number"
                          },
                          "units_sold": {
                            "type": "number"
                          },
                          "engagement_rate": {
                            "type": "number"
                          },
                          "conversion_rate": {
                            "type": "number"
                          },
                          "avg_gmv_per_view": {
                            "type": "number"
                          },
                          "avg_order_value": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "video_id": "7606791381478018318",
                          "handle": "example_creator",
                          "title": "Product review video",
                          "post_time": "02/14/2026",
                          "product_id": "product_id_123",
                          "gmv": 4315.91,
                          "commission": 176.88,
                          "views": 543850,
                          "likes": 3841,
                          "comments": 49,
                          "units_sold": 165,
                          "engagement_rate": 0.72,
                          "conversion_rate": 0.0303,
                          "avg_gmv_per_view": 0.0079,
                          "avg_order_value": 26.16
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/slideshows/list": {
      "post": {
        "operationId": "slideshows",
        "summary": "Carousel Search",
        "description": "Retrieve shoppable slideshows (TikTok photo-mode posts) and performance metrics. Slideshows are tracked separately from videos — a slideshow never appears in **Videos Search** and vice versa.",
        "tags": [
          "CRM & Content"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#slideshows"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/slideshows/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "Pagination controls (server max page_size is 100)"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "Pagination controls (server max page_size is 100)"
                  },
                  "just_count": {
                    "type": "boolean",
                    "description": "if true, returns only total_count (no results)"
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "handle": {
                        "type": "string"
                      },
                      "product_filter": {
                        "type": "string"
                      },
                      "campaign_id": {
                        "type": "string"
                      },
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      }
                    }
                  },
                  "sort_by": {
                    "type": "string",
                    "enum": [
                      "gmv",
                      "post_time",
                      "view_count",
                      "like_count",
                      "comment_count",
                      "units_sold",
                      "ctr",
                      "engagement_rate"
                    ],
                    "description": "`gmv`, `post_time`, `view_count`, `like_count`, `comment_count`, `units_sold`, `ctr`, `engagement_rate`. Ad metrics (`roi`, `cpa`, `ad_spend`) are video-only and not available here."
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "ASC",
                      "DESC"
                    ],
                    "description": "`ASC` or `DESC`"
                  },
                  "handle": {
                    "type": "string",
                    "description": "*(optional)* Filter by creator handle"
                  },
                  "product_filter": {
                    "type": "string",
                    "description": "*(optional)* Filter by product ID"
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by campaign"
                  },
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "*(optional)* Filters by **post time** (YYYY-MM-DD)"
                  }
                }
              },
              "example": {
                "page_size": 20,
                "page_number": 1,
                "just_count": false,
                "filters": {
                  "sort_by": "gmv",
                  "sort_direction": "desc",
                  "handle": "example_creator",
                  "product_filter": "product_id_123",
                  "campaign_id": "campaign_id_123",
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "shop_id": {
                                "type": "string"
                              },
                              "video_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "post_time": {
                                "type": "string"
                              },
                              "view_count": {
                                "type": "integer"
                              },
                              "units_sold": {
                                "type": "number"
                              },
                              "ctr": {
                                "type": "number"
                              },
                              "like_count": {
                                "type": "integer"
                              },
                              "comment_count": {
                                "type": "integer"
                              },
                              "engagement_rate": {
                                "type": "number"
                              },
                              "title": {
                                "type": "string"
                              },
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "products": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "product": {
                                "type": "string"
                              },
                              "slideshow_url": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "page_offset": {
                          "type": "number"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "shop_id": "your_shop_id_here",
                            "video_id": "7656557180228799758",
                            "handle": "example_creator",
                            "gmv": 5236.06,
                            "post_time": "07/28/2026",
                            "view_count": 1367653,
                            "units_sold": 310,
                            "ctr": 0.0162,
                            "like_count": 6382,
                            "comment_count": 169,
                            "engagement_rate": 0.48,
                            "title": "3 ways to style this",
                            "campaign_id": null,
                            "products": [
                              "product_id_123"
                            ],
                            "product": "product_id_123",
                            "slideshow_url": "https://tiktok.com/@example_creator/photo/7656557180228799758"
                          }
                        ],
                        "has_more": false,
                        "page_size": 20,
                        "page_offset": 0
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/timeseries/slideshows": {
      "post": {
        "operationId": "tsSlideshows",
        "summary": "Carousel Timeseries Search",
        "description": "Search slideshows by performance over a specific date range — the windowed counterpart to **Carousel Search**. Returns per-slideshow GMV, views, engagement and conversion metrics earned during the period. Supports filtering by handle, product and campaign.",
        "tags": [
          "CRM & Content"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ts-slideshows"
        },
        "security": [
          {
            "apiKey": [
              "POST /timeseries/slideshows"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "Pagination controls"
                  },
                  "search_params": {
                    "type": "object",
                    "properties": {
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "handle": {
                        "type": "string"
                      },
                      "product_id": {
                        "type": "string"
                      },
                      "campaign_id": {
                        "type": "string"
                      }
                    }
                  },
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date"
                      },
                      "to": {
                        "type": "string",
                        "format": "date"
                      }
                    },
                    "description": "Object with `from` and `to` dates (YYYY-MM-DD). Required — defines the aggregation window."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "Field to sort by (e.g. `gmv`, `views`, `likes`, `comments`, `units_sold`, `commission`)"
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "ASC",
                      "DESC"
                    ],
                    "description": "`ASC` or `DESC`"
                  },
                  "handle": {
                    "type": "string",
                    "description": "*(optional)* Filter by creator handle"
                  },
                  "product_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by product ID"
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* Filter by campaign"
                  }
                }
              },
              "example": {
                "page_size": 10,
                "page_number": 1,
                "search_params": {
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "sort_by": "gmv",
                  "sort_direction": "DESC",
                  "handle": "example_creator",
                  "product_id": "product_id_123",
                  "campaign_id": "campaign_id_123"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "video_id": {
                            "type": "string"
                          },
                          "handle": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "post_time": {
                            "type": "string"
                          },
                          "product_id": {
                            "type": "string"
                          },
                          "gmv": {
                            "type": "number"
                          },
                          "commission": {
                            "type": "number"
                          },
                          "views": {
                            "type": "number"
                          },
                          "likes": {
                            "type": "number"
                          },
                          "comments": {
                            "type": "number"
                          },
                          "units_sold": {
                            "type": "number"
                          },
                          "engagement_rate": {
                            "type": "number"
                          },
                          "conversion_rate": {
                            "type": "number"
                          },
                          "avg_gmv_per_view": {
                            "type": "number"
                          },
                          "avg_order_value": {
                            "type": "number"
                          },
                          "slideshow_link": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "video_id": "7656557180228799758",
                          "handle": "example_creator",
                          "title": "3 ways to style this",
                          "post_time": "07/28/2026",
                          "product_id": "product_id_123",
                          "gmv": 4315.91,
                          "commission": 0,
                          "views": 543850,
                          "likes": 3841,
                          "comments": 49,
                          "units_sold": 165,
                          "engagement_rate": 0.72,
                          "conversion_rate": 0.0303,
                          "avg_gmv_per_view": 0.0079,
                          "avg_order_value": 26.16,
                          "slideshow_link": "https://tiktok.com/@example_creator/photo/7656557180228799758"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/lives/list": {
      "post": {
        "operationId": "lives",
        "summary": "LIVE Stream Search",
        "description": "Retrieve live streams and performance metrics.",
        "tags": [
          "CRM & Content"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lives"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/lives/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer"
                  },
                  "page_number": {
                    "type": "integer"
                  },
                  "just_count": {
                    "type": "boolean",
                    "description": "if true, returns only total_count (no results)"
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "sort_by": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "handle": {
                        "type": "string"
                      },
                      "product_filter": {
                        "type": "string"
                      },
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "affiliate_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number",
                            "description": "platform-wide 30-day GMV"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_followers": {
                            "type": "number"
                          },
                          "max_followers": {
                            "type": "number"
                          }
                        }
                      },
                      "shop_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number",
                            "description": "shop-specific lifetime GMV"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_video_gmv": {
                            "type": "number"
                          },
                          "max_video_gmv": {
                            "type": "number"
                          },
                          "min_live_gmv": {
                            "type": "number"
                          },
                          "max_live_gmv": {
                            "type": "number"
                          },
                          "min_units_sold": {
                            "type": "number"
                          },
                          "max_units_sold": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "page_size": 100,
                "page_number": 1,
                "just_count": false,
                "filters": {
                  "sort_by": "gmv",
                  "sort_direction": "desc",
                  "handle": "example_creator",
                  "product_filter": "product_id_123",
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "affiliate_performance": {
                    "min_gmv": 100,
                    "max_gmv": 100000,
                    "min_followers": 1000,
                    "max_followers": 500000
                  },
                  "shop_performance": {
                    "min_gmv": 0,
                    "max_gmv": 100000,
                    "min_video_gmv": 0,
                    "max_video_gmv": 100000,
                    "min_live_gmv": 0,
                    "max_live_gmv": 100000,
                    "min_units_sold": 0,
                    "max_units_sold": 10000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "shop_id": {
                                "type": "string"
                              },
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "live_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "title": {
                                "type": "string"
                              },
                              "start_time": {
                                "type": "string"
                              },
                              "duration": {
                                "type": "number"
                              },
                              "units_sold": {
                                "type": "number"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "views": {
                                "type": "number"
                              },
                              "likes": {
                                "type": "number"
                              },
                              "comments": {
                                "type": "number"
                              },
                              "ctr": {
                                "type": "number"
                              },
                              "products": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "products_stats": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "product_id": {
                                      "type": "string"
                                    },
                                    "gmv": {
                                      "type": "number"
                                    },
                                    "units_sold": {
                                      "type": "number"
                                    },
                                    "impressions": {
                                      "type": "number"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "page_offset": {
                          "type": "number"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "shop_id": "your_shop_id_here",
                            "campaign_id": null,
                            "live_id": "7610921877288061726",
                            "handle": "example_creator",
                            "title": "Product Demo LIVE",
                            "start_time": "02/25/2025",
                            "duration": 14869,
                            "units_sold": 22,
                            "gmv": 701.2,
                            "views": 87473,
                            "likes": 1539,
                            "comments": 133,
                            "ctr": 0.05,
                            "products": [
                              "product_id_123",
                              "product_id_456"
                            ],
                            "products_stats": [
                              {
                                "product_id": "product_id_123",
                                "gmv": 564.15,
                                "units_sold": 19,
                                "impressions": 13963
                              },
                              {
                                "product_id": "product_id_456",
                                "gmv": 137.05,
                                "units_sold": 3,
                                "impressions": 2567
                              }
                            ]
                          }
                        ],
                        "page_size": 100,
                        "page_offset": 0,
                        "sort_by": "gmv",
                        "sort_direction": "DESC",
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/spark/list": {
      "post": {
        "operationId": "spark",
        "summary": "Spark Ad Search",
        "description": "Retrieve spark ad codes shared with your store, with their authorization windows, status, and the joined performance data for each linked video.",
        "tags": [
          "TikTok Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#spark"
        },
        "security": [
          {
            "apiKey": [
              "POST /spark/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "All fields are optional; defaults are shown above. Each date-range filter also accepts flat keys (e.g. `shared_time_from`, `shared_time_to`), and `search_params` filters may be sent inline at the top level. Also callable over `GET` with query params.\n\n**Sortable columns (`sort_by`):** `gmv`, `ad_spend`, `roi`, `cpa`, `shared_time`, `created_at`, `auth_start_time`, `auth_end_time`, `post_time`, `status` (nulls sort last).\n\n**Ad status values (`status`):** `NOT_ACTIVE`, `UNAVAILABLE`, `NOT_DELIVERYING`, `AUTHORIZATION_NEEDED`, `IN_QUEUE`, `DELIVERING`, `LEARNING`, `EXCLUDED`, `REJECTED`, `NOT_DELIVERING`, `REVIEWING`. This is the GMV Max delivery status (same as [GMV Max - List Creatives](https://cruva.com/docs/api#ads-creatives)); both `NOT_DELIVERYING` and the correctly-spelled `NOT_DELIVERING` exist upstream as distinct values.\n\n**Note:** Video matching requires the TikTok for Business API to be installed on the brand. Without it, we cannot join the underlying content data, so `video_id` and the `video_data` fields will be returned as `null`.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "max 100"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "1-based; overrides page_offset if set"
                  },
                  "page_offset": {
                    "type": "number"
                  },
                  "include_total": {
                    "type": "boolean",
                    "description": "run a COUNT and return total_count"
                  },
                  "just_count": {
                    "type": "boolean",
                    "description": "if true, returns only total_count (no results)"
                  },
                  "search_params": {
                    "type": "object",
                    "properties": {
                      "sort_by": {
                        "type": "string",
                        "description": "gmv | ad_spend | roi | cpa | shared_time | created_at | auth_start_time | auth_end_time | post_time | status"
                      },
                      "sort_direction": {
                        "type": "string",
                        "description": "ASC | DESC (nulls sort last)"
                      },
                      "handle": {
                        "type": "string",
                        "description": "case-insensitive substring match on creator handle"
                      },
                      "spark_code": {
                        "type": "string",
                        "description": "exact match"
                      },
                      "status": {
                        "type": "string",
                        "description": "GMV Max delivery status; single value or array"
                      },
                      "expired": {
                        "type": "boolean"
                      },
                      "video_ids": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "shared_time": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        },
                        "description": "when the code was shared"
                      },
                      "auth_time": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        },
                        "description": "auth_start_time >= from AND auth_end_time <= to"
                      },
                      "post_time": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        },
                        "description": "when the video was posted"
                      }
                    }
                  }
                }
              },
              "example": {
                "page_size": 10,
                "page_number": 1,
                "page_offset": 0,
                "include_total": true,
                "just_count": false,
                "search_params": {
                  "sort_by": "gmv",
                  "sort_direction": "DESC",
                  "handle": "smith",
                  "spark_code": "#aBcD...==",
                  "status": "DELIVERING",
                  "expired": false,
                  "video_ids": [
                    "7600000000000000001",
                    "7600000000000000002"
                  ],
                  "shared_time": {
                    "from": "2026-01-01",
                    "to": "2026-12-31"
                  },
                  "auth_time": {
                    "from": "2026-01-01",
                    "to": "2026-12-31"
                  },
                  "post_time": {
                    "from": "2026-01-01",
                    "to": "2026-12-31"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "shop_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "spark_code": {
                                "type": "string",
                                "description": "TikTok spark authorization code."
                              },
                              "shared_time": {
                                "type": "string",
                                "description": "When the spark code was shared with the brand (MM/DD/YYYY). `shared_time` is the canonical alias of `created_at`."
                              },
                              "video_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "TikTok video id, or `null` if not yet linked."
                              },
                              "auth_start_time": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Authorization window (MM/DD/YYYY), or `null`."
                              },
                              "auth_end_time": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Authorization window (MM/DD/YYYY), or `null`."
                              },
                              "status": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "GMV Max ad delivery status — the same values as [GMV Max - List Creatives](https://cruva.com/docs/api#ads-creatives): `NOT_ACTIVE`, `UNAVAILABLE`, `NOT_DELIVERYING`, `AUTHORIZATION_NEEDED`, `IN_QUEUE`, `DELIVERING`, `LEARNING`, `EXCLUDED`, `REJECTED`, `NOT_DELIVERING`, `REVIEWING`. (Both `NOT_DELIVERYING` and the correctly-spelled `NOT_DELIVERING` exist upstream as distinct values.) `null` when the code isn't running as a GMV Max ad."
                              },
                              "expired": {
                                "type": "boolean",
                                "description": "Whether the spark code is expired."
                              },
                              "ad_spend": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "GMV Max delivery metrics for the ad, or `null` when the code isn't running as a GMV Max ad. `cpa` is cost per acquisition. Sortable via `sort_by`."
                              },
                              "roi": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "GMV Max delivery metrics for the ad, or `null` when the code isn't running as a GMV Max ad. `cpa` is cost per acquisition. Sortable via `sort_by`."
                              },
                              "cpa": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "GMV Max delivery metrics for the ad, or `null` when the code isn't running as a GMV Max ad. `cpa` is cost per acquisition. Sortable via `sort_by`."
                              },
                              "video_link": {
                                "type": "string",
                                "description": "`https://tiktok.com/@{handle}/video/{video_id}` (literal `None` when `video_id` is null)."
                              },
                              "video_data": {
                                "type": [
                                  "object",
                                  "null"
                                ],
                                "properties": {
                                  "shop_id": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "video_id": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "handle": {
                                    "type": "string"
                                  },
                                  "campaign_id": {
                                    "type": "string"
                                  },
                                  "title": {
                                    "type": "string"
                                  },
                                  "post_time": {
                                    "type": "string"
                                  },
                                  "analysis_time": {
                                    "type": "string"
                                  },
                                  "gmv": {
                                    "type": "number"
                                  },
                                  "commission": {
                                    "type": "number"
                                  },
                                  "ctr": {
                                    "type": "number"
                                  },
                                  "engagement_rate": {
                                    "type": "number"
                                  },
                                  "view_count": {
                                    "type": "integer"
                                  },
                                  "like_count": {
                                    "type": "integer"
                                  },
                                  "comment_count": {
                                    "type": "integer"
                                  },
                                  "units_sold": {
                                    "type": "number"
                                  },
                                  "products": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "description": "Joined content row (matched on `shop_id` + `video_id`) with analytics fields, or `null` when no matching content row exists. Timestamps are ISO `YYYY-MM-DDTHH:MM:SS`."
                              }
                            }
                          }
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "page_offset": {
                          "type": "number"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "total_count": {
                          "type": [
                            "integer",
                            "null"
                          ],
                          "description": "Total matching rows; `null` when `include_total` is false."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "shop_id": "your_shop_id_here",
                            "handle": "example_creator",
                            "spark_code": "#aBcD1234eFgH5678iJkL90mNoPqRsTuVwXyZ+/aBcD==",
                            "shared_time": "06/11/2026",
                            "video_id": "7600000000000000111",
                            "auth_start_time": "06/11/2026",
                            "auth_end_time": "06/11/2027",
                            "status": "DELIVERING",
                            "expired": false,
                            "ad_spend": 437.19,
                            "roi": 2.04,
                            "cpa": 14.1,
                            "video_link": "https://tiktok.com/@example_creator/video/7600000000000000111",
                            "video_data": {
                              "shop_id": "your_shop_id_here",
                              "video_id": "7600000000000000111",
                              "handle": "example_creator",
                              "campaign_id": "6b2c3d4e5f60718293a4b5c7",
                              "title": "5 AMAZING smells in this package!",
                              "post_time": "2026-05-31T06:33:49",
                              "analysis_time": "2026-06-01T22:48:23.347710",
                              "gmv": 507.39,
                              "commission": 77.73,
                              "ctr": 0.0451,
                              "engagement_rate": 0.69,
                              "view_count": 19888,
                              "like_count": 129,
                              "comment_count": 8,
                              "units_sold": 62,
                              "products": [
                                "1700000000000000002"
                              ]
                            }
                          },
                          {
                            "shop_id": "your_shop_id_here",
                            "handle": "no_video_creator",
                            "spark_code": "#zZyYxXwWvVuUtTsSrRqQpPoOnN==",
                            "shared_time": "06/08/2026",
                            "video_id": null,
                            "auth_start_time": null,
                            "auth_end_time": null,
                            "status": null,
                            "expired": false,
                            "ad_spend": null,
                            "roi": null,
                            "cpa": null,
                            "video_link": "https://tiktok.com/@no_video_creator/video/None",
                            "video_data": null
                          }
                        ],
                        "page_size": 10,
                        "page_offset": 0,
                        "sort_by": "shared_time",
                        "sort_direction": "DESC",
                        "has_more": true,
                        "total_count": 40
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/ads/campaigns": {
      "post": {
        "operationId": "adsCampaigns",
        "summary": "GMV Max - List Campaigns",
        "description": "List the shop's GMV Max ad campaigns with metrics aggregated over a date range, plus shop-level summary totals with a prior-period comparison. To drill into a campaign's per-video creatives, pass its `campaign_id` to [GMV Max - List Creatives](https://cruva.com/docs/api#ads-creatives).",
        "tags": [
          "TikTok Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ads-campaigns"
        },
        "security": [
          {
            "apiKey": [
              "POST /ads/campaigns"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Request keys accept both `snake_case` and `camelCase` (`page_size`/`pageSize`, `sort_by`/`sortBy`, `date_range`/`dateRange`, `sort_direction`/`sortDir`). Also reachable at the `/v1/ads/campaigns` alias.\n\nThe prior-period comparison window is computed automatically: the same number of days immediately preceding `date_range`. Invalid `sort_by` values silently fall back to `ad_spend`.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` bounds. Returns `400 \"Missing date_range (from/to)\"` if absent."
                      },
                      "to": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` bounds. Returns `400 \"Missing date_range (from/to)\"` if absent."
                      }
                    },
                    "description": "required",
                    "required": [
                      "from",
                      "to"
                    ]
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page number. Defaults to `1`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* Results per page. Defaults to `10`, clamped to `1`–`100`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* One of `ad_spend`, `ad_revenue`, `orders`, `campaign_name`, `operation_status`, `budget`, `roas_target`. Invalid values fall back to `ad_spend`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* `ASC` or `DESC` (nulls sort last). Defaults to `DESC`."
                  }
                },
                "required": [
                  "date_range"
                ]
              },
              "example": {
                "date_range": {
                  "from": "2026-01-01",
                  "to": "2026-12-31"
                },
                "page": 1,
                "page_size": 10,
                "sort_by": "ad_spend",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "totals": {
                          "type": "object",
                          "properties": {
                            "ad_spend": {
                              "type": "number"
                            },
                            "ad_roi": {
                              "type": "number"
                            },
                            "ad_revenue": {
                              "type": "number"
                            },
                            "prev": {
                              "type": "object",
                              "properties": {
                                "ad_spend": {
                                  "type": "number"
                                },
                                "ad_roi": {
                                  "type": "number"
                                },
                                "ad_revenue": {
                                  "type": "number"
                                }
                              },
                              "description": "The same three fields for the equal-length prior period, for trend / % change."
                            }
                          },
                          "description": "Shop-wide ad summary over the range (from `shop_performance`): `ad_spend` (total ad spend), `ad_revenue` (total ad-attributed revenue), and `ad_roi` (`ad_revenue / ad_spend`, `0` if no spend)."
                        },
                        "campaigns": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "campaign_id": {
                                "type": "string",
                                "description": "GMV Max campaign id."
                              },
                              "campaign_name": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Campaign name, or `null`."
                              },
                              "operation_status": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Campaign state, e.g. `ENABLE`, `DISABLE`. May be `null`."
                              },
                              "budget": {
                                "type": "number",
                                "description": "Campaign budget."
                              },
                              "roas_target": {
                                "type": "number",
                                "description": "Target return on ad spend."
                              },
                              "schedule_type": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "e.g. `SCHEDULE_FROM_NOW`, `SCHEDULE_START_END`. May be `null`."
                              },
                              "schedule_start_time": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Schedule window as datetime strings, or `null`."
                              },
                              "schedule_end_time": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Schedule window as datetime strings, or `null`."
                              },
                              "product_specific_type": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "e.g. `CUSTOMIZED_PRODUCTS`. May be `null`."
                              },
                              "auto_budget_enabled": {
                                "type": "boolean",
                                "description": "Whether auto-budget is enabled."
                              },
                              "store_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "TikTok store id, or `null`."
                              },
                              "item_group_ids": {
                                "type": "string",
                                "description": "Targeted product/item group id(s). Optionally pass as `product_ids` to [GMV Max - List Creatives](https://cruva.com/docs/api#ads-creatives) — though `campaign_id` is the direct way to list a campaign's creatives."
                              },
                              "ad_spend": {
                                "type": "number",
                                "description": "Metrics aggregated over the range."
                              },
                              "ad_revenue": {
                                "type": "number",
                                "description": "Metrics aggregated over the range."
                              },
                              "ad_roi": {
                                "type": "number",
                                "description": "`ad_revenue / ad_spend` (`0` if no spend)."
                              },
                              "orders": {
                                "type": "number",
                                "description": "Metrics aggregated over the range."
                              },
                              "cost_per_order": {
                                "type": "number",
                                "description": "`ad_spend / orders` (`0` if no orders)."
                              }
                            }
                          },
                          "description": "Page of campaigns. Campaigns with no spend in the range still appear (left-joined) with zeroed metrics."
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Counts all campaigns for the shop, independent of the date range."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "totals": {
                          "ad_spend": 412532.45,
                          "ad_roi": 7.94,
                          "ad_revenue": 3275489.1,
                          "prev": {
                            "ad_spend": 388110.22,
                            "ad_roi": 7.41,
                            "ad_revenue": 2876300.55
                          }
                        },
                        "campaigns": [
                          {
                            "campaign_id": "1820000000000000001",
                            "campaign_name": "Pillow Bundle 2&4pk",
                            "operation_status": "ENABLE",
                            "budget": 8000,
                            "roas_target": 5.7,
                            "schedule_type": "SCHEDULE_FROM_NOW",
                            "schedule_start_time": "2025-01-16 18:18:59",
                            "schedule_end_time": "2035-01-14 18:18:59",
                            "product_specific_type": "CUSTOMIZED_PRODUCTS",
                            "auto_budget_enabled": false,
                            "store_id": "7400000000000000001",
                            "item_group_ids": "1729000000000000001",
                            "ad_spend": 172521.52,
                            "ad_revenue": 1516512.52,
                            "ad_roi": 8.79,
                            "orders": 40103,
                            "cost_per_order": 4.3
                          },
                          {
                            "campaign_id": "1820000000000000002",
                            "campaign_name": "Pillow 4pk Promo",
                            "operation_status": "ENABLE",
                            "budget": 2000,
                            "roas_target": 6,
                            "schedule_type": "SCHEDULE_START_END",
                            "schedule_start_time": "2025-11-13 00:00:00",
                            "schedule_end_time": "2038-01-01 00:00:00",
                            "product_specific_type": "CUSTOMIZED_PRODUCTS",
                            "auto_budget_enabled": false,
                            "store_id": "7400000000000000001",
                            "item_group_ids": "1731000000000000002",
                            "ad_spend": 121487.72,
                            "ad_revenue": 736974.12,
                            "ad_roi": 6.07,
                            "orders": 16030,
                            "cost_per_order": 7.58
                          }
                        ],
                        "total_count": 166,
                        "page": 1,
                        "page_size": 10,
                        "sort_by": "ad_spend",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "campaigns require a date range; missing or malformed shop header",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "campaigns require a date range",
                    "value": {
                      "error": "Missing date_range (from/to)"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "shop scope / plan failures",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/ads/creatives": {
      "post": {
        "operationId": "adsCreatives",
        "summary": "GMV Max - List Creatives",
        "description": "List per-creative (per-video) GMV Max ad performance aggregated over a date range, joined to video metadata. To list a specific campaign's creatives, pass its `campaign_id` (from [GMV Max - List Campaigns](https://cruva.com/docs/api#ads-campaigns)).",
        "tags": [
          "TikTok Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ads-creatives"
        },
        "security": [
          {
            "apiKey": [
              "POST /ads/creatives"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "All fields are optional. Request keys accept both `snake_case` and `camelCase` (`campaign_id`/`campaignId`, `page_size`/`pageSize`, `product_ids`/`productIds`, `video_ids`/`video_id`/`videoIds`, `sort_by`/`sortBy`, `sort_direction`/`sortDir`). Also reachable at the `/v1/ads/creatives` alias.\n\nTwo independent date ranges:\n\n`performance_date` is the **metrics window**: every ad metric is aggregated over exactly those days (`ad_spend`/`gross_revenue`/`orders` etc. are sums; `roi`, `cpa`, and `click_rate` are recomputed as ratio-of-sums over the window; `ad_click_rate`, `conversion_rate`, and the view rates are weighted averages of the daily values). Either bound may be sent alone — the missing side defaults. When omitted entirely, the window defaults to the **trailing 6 months**, the deepest range with daily data. `status` is the latest value observed within the window; the same creative returns different metrics for different windows.\n\n`posted_date` filters **which videos are included**, by post date — independent of the metrics window (\"videos posted in May, measured over June\" is valid). The legacy `date_range` key is an alias of `posted_date` (its original meaning), so pre-existing integrations behave exactly as before.\n\nThe `campaign_id` and product/video filters combine — send `campaign_id` alone, products alone, both (a campaign narrowed to specific products), or neither (the whole shop).\n\n**Sortable columns (`sort_by`):** `date_posted`, `ad_spend`, `gross_revenue`, `roi`, `cpa`, `orders`, `cost_per_order`, `impressions`, `clicks`, `click_rate`, `ad_click_rate`, `conversion_rate`, `view_rate_2s`, `view_rate_6s`, `view_count`. Invalid values fall back to `ad_spend`.\n\n**Ad status values (`statuses`):** `NOT_ACTIVE`, `UNAVAILABLE`, `NOT_DELIVERYING`, `AUTHORIZATION_NEEDED`, `IN_QUEUE`, `DELIVERING`, `LEARNING`, `EXCLUDED`, `REJECTED`, `NOT_DELIVERING`, `REVIEWING`. (Both `NOT_DELIVERYING` and the correctly-spelled `NOT_DELIVERING` exist upstream as distinct values.) The response also returns `available_statuses` — the statuses actually present for the current shop/campaign/product/video/date scope, before the `statuses` filter is applied.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "performance_date": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date",
                        "description": "*(optional)* `YYYY-MM-DD` bounds of the **metrics window** — all ad metrics are aggregated over these days. Either bound may be sent alone (`from` defaults to 6 months ago, `to` to today). Omit entirely for the trailing 6 months."
                      },
                      "to": {
                        "type": "string",
                        "format": "date",
                        "description": "*(optional)* `YYYY-MM-DD` bounds of the **metrics window** — all ad metrics are aggregated over these days. Either bound may be sent alone (`from` defaults to 6 months ago, `to` to today). Omit entirely for the trailing 6 months."
                      }
                    },
                    "description": "optional; METRICS window, defaults to trailing 6 months"
                  },
                  "posted_date": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date",
                        "description": "*(optional)* `YYYY-MM-DD` bounds filtering videos by **post date**; videos with an unknown post date are excluded when set. Either bound may be sent alone. The legacy `date_range` key is an alias of this field."
                      },
                      "to": {
                        "type": "string",
                        "format": "date",
                        "description": "*(optional)* `YYYY-MM-DD` bounds filtering videos by **post date**; videos with an unknown post date are excluded when set. Either bound may be sent alone. The legacy `date_range` key is an alias of this field."
                      }
                    },
                    "description": "optional; filters videos by post date"
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page number. Defaults to `1`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* Results per page. Defaults to `5`, clamped to `1`–`1000`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* See the sortable list in the notes. Invalid values fall back to `ad_spend`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* `ASC` or `DESC` (nulls last). Defaults to `DESC`."
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* `string`. Restrict to a single GMV Max campaign (its `campaign_id` from [GMV Max - List Campaigns](https://cruva.com/docs/api#ads-campaigns)). Combines with the product/video filters."
                  },
                  "product_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* `string[]` or `string`. Restrict to these product IDs (e.g. a campaign's `item_group_ids`)."
                  },
                  "video_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* `string[]` or `string`. Look up specific creative video IDs."
                  },
                  "statuses": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* `string[]` or `string`. Filter by ad status (see notes). Omit for all."
                  }
                }
              },
              "example": {
                "performance_date": {
                  "from": "2026-06-01",
                  "to": "2026-06-30"
                },
                "posted_date": {
                  "from": "2026-05-01",
                  "to": "2026-05-31"
                },
                "page": 1,
                "page_size": 10,
                "sort_by": "ad_spend",
                "sort_direction": "DESC",
                "campaign_id": "1820000000000000001",
                "product_ids": [
                  "1729000000000000001"
                ],
                "video_ids": [
                  "7600000000000000111"
                ],
                "statuses": [
                  "DELIVERING"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "creatives": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "video_id": {
                                "type": "string",
                                "description": "TikTok video id."
                              },
                              "product_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Product the creative advertised, or `null`."
                              },
                              "status": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Ad status (see the status list in the notes) as last observed within the metrics window, or `null`."
                              },
                              "date_posted": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "format": "date",
                                "description": "Video post date `YYYY-MM-DD`, or `null`. Not affected by `date_range`."
                              },
                              "ad_spend": {
                                "type": "number",
                                "description": "Ad performance over the metrics window. `roi` and `cpa` are ratio-of-sums (window revenue ÷ window spend; window spend ÷ window orders)."
                              },
                              "gross_revenue": {
                                "type": "number",
                                "description": "Ad performance over the metrics window. `roi` and `cpa` are ratio-of-sums (window revenue ÷ window spend; window spend ÷ window orders)."
                              },
                              "roi": {
                                "type": "number",
                                "description": "Ad performance over the metrics window. `roi` and `cpa` are ratio-of-sums (window revenue ÷ window spend; window spend ÷ window orders)."
                              },
                              "cpa": {
                                "type": "number",
                                "description": "Ad performance over the metrics window. `roi` and `cpa` are ratio-of-sums (window revenue ÷ window spend; window spend ÷ window orders)."
                              },
                              "orders": {
                                "type": "number",
                                "description": "Order and reach counts over the metrics window. `cost_per_order` equals `cpa` at window grain."
                              },
                              "cost_per_order": {
                                "type": "number",
                                "description": "Order and reach counts over the metrics window. `cost_per_order` equals `cpa` at window grain."
                              },
                              "impressions": {
                                "type": "number",
                                "description": "Order and reach counts over the metrics window. `cost_per_order` equals `cpa` at window grain."
                              },
                              "clicks": {
                                "type": "number",
                                "description": "Order and reach counts over the metrics window. `cost_per_order` equals `cpa` at window grain."
                              },
                              "click_rate": {
                                "type": "number",
                                "description": "Percentages (e.g. `1.87` = 1.87%). `click_rate` is exact over the window (clicks ÷ impressions); the others are impression/click-weighted averages of the daily values."
                              },
                              "ad_click_rate": {
                                "type": "number",
                                "description": "Percentages (e.g. `1.87` = 1.87%). `click_rate` is exact over the window (clicks ÷ impressions); the others are impression/click-weighted averages of the daily values."
                              },
                              "conversion_rate": {
                                "type": "number",
                                "description": "Percentages (e.g. `1.87` = 1.87%). `click_rate` is exact over the window (clicks ÷ impressions); the others are impression/click-weighted averages of the daily values."
                              },
                              "view_rate_2s": {
                                "type": "number",
                                "description": "Percentages (e.g. `1.87` = 1.87%). `click_rate` is exact over the window (clicks ÷ impressions); the others are impression/click-weighted averages of the daily values."
                              },
                              "view_rate_6s": {
                                "type": "number",
                                "description": "Percentages (e.g. `1.87` = 1.87%). `click_rate` is exact over the window (clicks ÷ impressions); the others are impression/click-weighted averages of the daily values."
                              },
                              "handle": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Creator handle, or `null` if no matching content row."
                              },
                              "title": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Video caption/title, or `null`."
                              },
                              "view_count": {
                                "type": "integer",
                                "description": "Organic video views."
                              },
                              "url": {
                                "type": "string",
                                "description": "`https://www.tiktok.com/@{handle}/video/{video_id}` (or `.../video/{video_id}` when the handle is unknown). `video_link` is an alias of `url`."
                              },
                              "video_link": {
                                "type": "string",
                                "description": "`https://www.tiktok.com/@{handle}/video/{video_id}` (or `.../video/{video_id}` when the handle is unknown). `video_link` is an alias of `url`."
                              }
                            }
                          },
                          "description": "Page of per-video creatives."
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total matching creatives within the status-filter scope."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "available_statuses": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Distinct statuses present in the base scope (shop + campaign + products + videos + date) before the `statuses` filter — drives a status-filter UI."
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "creatives": [
                          {
                            "video_id": "7600000000000000111",
                            "product_id": "1729000000000000001",
                            "status": "UNAVAILABLE",
                            "date_posted": "2025-12-23",
                            "ad_spend": 349869.26,
                            "gross_revenue": 409347.04,
                            "roi": 1.17,
                            "cpa": 34.62,
                            "orders": 10105,
                            "cost_per_order": 34.62,
                            "impressions": 8847221,
                            "clicks": 165403,
                            "click_rate": 1.87,
                            "ad_click_rate": 2.03,
                            "conversion_rate": 6.1,
                            "view_rate_2s": 42.35,
                            "view_rate_6s": 21.08,
                            "handle": "ava_wellness",
                            "title": "Oop the gym crowd is gonna be salty about this one",
                            "view_count": 22165182,
                            "url": "https://www.tiktok.com/@ava_wellness/video/7600000000000000111",
                            "video_link": "https://www.tiktok.com/@ava_wellness/video/7600000000000000111"
                          },
                          {
                            "video_id": "7600000000000000222",
                            "product_id": "1729000000000000002",
                            "status": "DELIVERING",
                            "date_posted": "2026-04-24",
                            "ad_spend": 258095.2,
                            "gross_revenue": 281323.77,
                            "roi": 1.09,
                            "cpa": 18.11,
                            "orders": 14251,
                            "cost_per_order": 18.11,
                            "impressions": 6120044,
                            "clicks": 142880,
                            "click_rate": 2.33,
                            "ad_click_rate": 2.51,
                            "conversion_rate": 9.97,
                            "view_rate_2s": 39.4,
                            "view_rate_6s": 18.62,
                            "handle": "noah.digest",
                            "title": "If you bloat after ANYTHING even healthy food, this is for u",
                            "view_count": 15978701,
                            "url": "https://www.tiktok.com/@noah.digest/video/7600000000000000222",
                            "video_link": "https://www.tiktok.com/@noah.digest/video/7600000000000000222"
                          }
                        ],
                        "total_count": 1284,
                        "page": 1,
                        "page_size": 10,
                        "available_statuses": [
                          "AUTHORIZATION_NEEDED",
                          "DELIVERING",
                          "EXCLUDED",
                          "IN_QUEUE",
                          "LEARNING",
                          "NOT_ACTIVE",
                          "NOT_DELIVERYING",
                          "REJECTED",
                          "UNAVAILABLE"
                        ],
                        "sort_by": "ad_spend",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "missing or malformed shop header",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "shop scope / plan failures",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/ads/excluded-creatives": {
      "post": {
        "operationId": "adsExcludedCreatives",
        "summary": "GMV Max - List Excluded Creatives",
        "description": "List creatives currently excluded from GMV Max campaigns—the same active exclusion records shown in Ads → TikTok Ads → Excluded. Includes manual exclusions, moderation scans, and automation-rule exclusions.",
        "tags": [
          "TikTok Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ads-excluded-creatives"
        },
        "security": [
          {
            "apiKey": [
              "POST /ads/excluded-creatives"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Only active exclusions are returned. Filters combine. Request keys accept `snake_case` and common `camelCase` aliases; the endpoint is also callable with `GET` query parameters and at the `/v1/ads/excluded-creatives` alias.\n\nAdd `\"format\": \"csv\"` for a presigned CSV download link; `columns` selects fields and `csv_limit` caps exported rows.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict to one GMV Max campaign."
                  },
                  "video_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* TikTok video ID or array of IDs."
                  },
                  "rule_id": {
                    "type": "string",
                    "description": "*(optional)* Exclusion source ID. Manual exclusions use `manual`; moderation scan IDs begin with `moderation_scan`."
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page and results per page. Defaults to `1` / `20`; max page size is `100`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page and results per page. Defaults to `1` / `20`; max page size is `100`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* Sort using a key shown above and `ASC` or `DESC`. Defaults to `created_at DESC`; nulls sort last."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* Sort using a key shown above and `ASC` or `DESC`. Defaults to `created_at DESC`; nulls sort last."
                  }
                }
              },
              "example": {
                "campaign_id": "1820000000000000001",
                "video_ids": [
                  "7600000000000000111"
                ],
                "rule_id": "manual",
                "page": 1,
                "page_size": 20,
                "sort_by": "created_at",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "exclusions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "video_id": {
                                "type": "string"
                              },
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "GMV Max campaign identity. `campaign_name` is best-effort and may be `null`."
                              },
                              "campaign_name": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "GMV Max campaign identity. `campaign_name` is best-effort and may be `null`."
                              },
                              "product_ids": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Product IDs recorded when the creative was excluded."
                              },
                              "handle": {
                                "type": "string"
                              },
                              "title": {
                                "type": "string"
                              },
                              "url": {
                                "type": "string"
                              },
                              "video_link": {
                                "type": "string"
                              },
                              "rule_id": {
                                "type": "string",
                                "description": "Where the exclusion came from and its recorded explanation."
                              },
                              "rule_name": {
                                "type": "string",
                                "description": "Where the exclusion came from and its recorded explanation."
                              },
                              "reason": {
                                "type": "string",
                                "description": "Where the exclusion came from and its recorded explanation."
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "view_count": {
                                "type": [
                                  "integer",
                                  "null"
                                ],
                                "description": "Joined organic video metrics; numeric fields default to zero when no content row is available, while `ctr` may be `null`."
                              },
                              "like_count": {
                                "type": [
                                  "integer",
                                  "null"
                                ],
                                "description": "Joined organic video metrics; numeric fields default to zero when no content row is available, while `ctr` may be `null`."
                              },
                              "comment_count": {
                                "type": [
                                  "integer",
                                  "null"
                                ],
                                "description": "Joined organic video metrics; numeric fields default to zero when no content row is available, while `ctr` may be `null`."
                              },
                              "video_gmv": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Joined organic video metrics; numeric fields default to zero when no content row is available, while `ctr` may be `null`."
                              },
                              "ctr": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Joined organic video metrics; numeric fields default to zero when no content row is available, while `ctr` may be `null`."
                              },
                              "units_sold": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Joined organic video metrics; numeric fields default to zero when no content row is available, while `ctr` may be `null`."
                              },
                              "post_time": {
                                "type": "string"
                              }
                            }
                          },
                          "description": "Page of active excluded creatives."
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total active exclusions matching the filters."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "exclusions": [
                          {
                            "video_id": "7600000000000000111",
                            "campaign_id": "1820000000000000001",
                            "campaign_name": "Pillow Bundle 2&4pk",
                            "product_ids": [
                              "1729000000000000001"
                            ],
                            "handle": "ava_wellness",
                            "title": "My honest review",
                            "url": "https://www.tiktok.com/@ava_wellness/video/7600000000000000111",
                            "video_link": "https://www.tiktok.com/@ava_wellness/video/7600000000000000111",
                            "rule_id": "manual",
                            "rule_name": "Manual",
                            "reason": "Excluded from creative table",
                            "created_at": "2026-09-10T17:42:13",
                            "view_count": 184221,
                            "like_count": 9221,
                            "comment_count": 304,
                            "video_gmv": 4132.19,
                            "ctr": 0.0431,
                            "units_sold": 281,
                            "post_time": "2026-08-28T14:03:00"
                          }
                        ],
                        "total_count": 37,
                        "page": 1,
                        "page_size": 20,
                        "sort_by": "created_at",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/ads/boosted-creatives": {
      "post": {
        "operationId": "adsBoostedCreatives",
        "summary": "GMV Max - List Boosted Creatives",
        "description": "List active GMV Max boost sessions—or full boost history—the same records shown in Ads → TikTok Ads → Boosted. Performance is measured from each session's starting baseline.",
        "tags": [
          "TikTok Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ads-boosted-creatives"
        },
        "security": [
          {
            "apiKey": [
              "POST /ads/boosted-creatives"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "By default only active sessions are returned. Set `include_ended` to `true` to include stopped/expired sessions and their `ended_at` / `exit_reason`. Filters combine. Also callable with `GET` query parameters and at the `/v1/ads/boosted-creatives` alias.\n\nUnlike the dashboard load, this public read endpoint does not make a live TikTok request; `active` reflects Cruva's latest recorded session state.\n\nAdd `\"format\": \"csv\"` for a presigned CSV download link; `columns` selects fields and `csv_limit` caps exported rows.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "include_ended": {
                    "type": "boolean",
                    "description": "*(optional)* Boolean. Defaults to `false` (active sessions only)."
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict by campaign, TikTok video IDs, and/or boost source rule."
                  },
                  "video_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Restrict by campaign, TikTok video IDs, and/or boost source rule."
                  },
                  "rule_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict by campaign, TikTok video IDs, and/or boost source rule."
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page and results per page. Defaults to `1` / `20`; max page size is `100`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page and results per page. Defaults to `1` / `20`; max page size is `100`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* Sort using a key shown above and `ASC` or `DESC`. Defaults to `created_at DESC`; nulls sort last."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* Sort using a key shown above and `ASC` or `DESC`. Defaults to `created_at DESC`; nulls sort last."
                  }
                }
              },
              "example": {
                "include_ended": false,
                "campaign_id": "1820000000000000001",
                "video_ids": [
                  "7600000000000000111"
                ],
                "rule_id": "manual",
                "page": 1,
                "page_size": 20,
                "sort_by": "created_at",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "sessions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "session_id": {
                                "type": "string"
                              },
                              "rule_id": {
                                "type": "string",
                                "description": "Boost source. Manual boosts use `rule_id: \"manual\"`."
                              },
                              "rule_name": {
                                "type": "string",
                                "description": "Boost source. Manual boosts use `rule_id: \"manual\"`."
                              },
                              "campaign_id": {
                                "type": "string"
                              },
                              "campaign_name": {
                                "type": "string"
                              },
                              "video_id": {
                                "type": "string"
                              },
                              "product_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "title": {
                                "type": "string"
                              },
                              "url": {
                                "type": "string"
                              },
                              "video_link": {
                                "type": "string"
                              },
                              "budget_per_day": {
                                "type": "number",
                                "description": "Daily boost budget."
                              },
                              "spend": {
                                "type": "number",
                                "description": "Performance generated since the boost began. ROAS is baseline revenue ÷ baseline spend."
                              },
                              "revenue": {
                                "type": "number",
                                "description": "Performance generated since the boost began. ROAS is baseline revenue ÷ baseline spend."
                              },
                              "orders": {
                                "type": "number",
                                "description": "Performance generated since the boost began. ROAS is baseline revenue ÷ baseline spend."
                              },
                              "roas": {
                                "type": "number",
                                "description": "Performance generated since the boost began. ROAS is baseline revenue ÷ baseline spend."
                              },
                              "active": {
                                "type": "boolean",
                                "description": "Recorded session lifecycle state and, for ended sessions, when and why it ended."
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "ended_at": {
                                "description": "Recorded session lifecycle state and, for ended sessions, when and why it ended."
                              },
                              "exit_reason": {
                                "description": "Recorded session lifecycle state and, for ended sessions, when and why it ended."
                              },
                              "view_count": {
                                "type": "integer"
                              },
                              "like_count": {
                                "type": "integer"
                              },
                              "comment_count": {
                                "type": "integer"
                              },
                              "video_gmv": {
                                "type": "number"
                              },
                              "ctr": {
                                "type": "number"
                              },
                              "units_sold": {
                                "type": "number"
                              },
                              "post_time": {
                                "type": "string"
                              }
                            }
                          },
                          "description": "Page of boost sessions. Active-only unless `include_ended` is true."
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total sessions matching the filters and active/history scope."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "include_ended": {
                          "type": "boolean"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "sessions": [
                          {
                            "session_id": "7599000000000000001",
                            "rule_id": "manual",
                            "rule_name": "Manual",
                            "campaign_id": "1820000000000000001",
                            "campaign_name": "Pillow Bundle 2&4pk",
                            "video_id": "7600000000000000111",
                            "product_id": "1729000000000000001",
                            "handle": "ava_wellness",
                            "title": "My honest review",
                            "url": "https://www.tiktok.com/@ava_wellness/video/7600000000000000111",
                            "video_link": "https://www.tiktok.com/@ava_wellness/video/7600000000000000111",
                            "budget_per_day": 50,
                            "spend": 183.27,
                            "revenue": 641.45,
                            "orders": 19,
                            "roas": 3.5,
                            "active": true,
                            "created_at": "2026-09-10T17:42:13",
                            "ended_at": null,
                            "exit_reason": null,
                            "view_count": 184221,
                            "like_count": 9221,
                            "comment_count": 304,
                            "video_gmv": 4132.19,
                            "ctr": 0.0431,
                            "units_sold": 281,
                            "post_time": "2026-08-28T14:03:00"
                          }
                        ],
                        "total_count": 8,
                        "page": 1,
                        "page_size": 20,
                        "include_ended": false,
                        "sort_by": "created_at",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/meta/campaigns": {
      "post": {
        "operationId": "metaCampaigns",
        "summary": "Meta Ads - List Campaigns",
        "description": "List the Meta ad campaigns containing ads pushed from Cruva, with metrics aggregated over a date range. **Cruva-pushed ads only** — this is not your whole Meta Ads account (see the [section overview](https://cruva.com/docs/api#meta-ads-about)). To drill into a campaign, pass its `campaign_id` to [Meta Ads - List Ad Sets](https://cruva.com/docs/api#meta-adsets) or [Meta Ads - List Ads](https://cruva.com/docs/api#meta-ads).",
        "tags": [
          "Meta Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#meta-campaigns"
        },
        "security": [
          {
            "apiKey": [
              "POST /meta/campaigns"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Request keys accept both `snake_case` and `camelCase`. Invalid `sort_by` values silently fall back to `spend`. Metrics are summed per campaign over the window from the daily ClickHouse mirror, so any date range is fast — no live Meta Graph API calls are made.\n\nAdd `\"format\": \"csv\"` to receive a presigned CSV download link instead of inline JSON (optionally with `columns` and `csv_limit`).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` bounds for the metrics window. Returns `400 \"Missing date_range (from/to)\"` if absent."
                      },
                      "to": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` bounds for the metrics window. Returns `400 \"Missing date_range (from/to)\"` if absent."
                      }
                    },
                    "description": "required",
                    "required": [
                      "from",
                      "to"
                    ]
                  },
                  "campaign_ids": {
                    "anyOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "string"
                      }
                    ],
                    "description": "*(optional)* Meta campaign id(s) to restrict to. Accepts a single string or an array."
                  },
                  "program_id": {
                    "type": "string",
                    "description": "*(optional)* Meta Ads program id (from [Meta Ads - List Programs](https://cruva.com/docs/api#meta-programs)). Only counts ads attributed to that program."
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page, results per page (default 10, max 100)."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* 1-based page, results per page (default 10, max 100)."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* Sort key (see request body) and `ASC`/`DESC`. Defaults: `spend` `DESC`, nulls last."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* Sort key (see request body) and `ASC`/`DESC`. Defaults: `spend` `DESC`, nulls last."
                  }
                },
                "required": [
                  "date_range"
                ]
              },
              "example": {
                "date_range": {
                  "from": "2026-07-01",
                  "to": "2026-07-31"
                },
                "campaign_ids": [
                  "120210000000000001"
                ],
                "program_id": "66b1f0aa77cc00112233dd01",
                "page": 1,
                "page_size": 10,
                "sort_by": "spend",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "campaigns": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Meta campaign id, or `null` for spend rows the mirror couldn't attribute to a campaign."
                              },
                              "campaign_name": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Campaign name as stamped at push time, or `null` when no Cruva push ever recorded a name for it (e.g. an entity created outside Cruva)."
                              },
                              "pushed_ads": {
                                "type": "number",
                                "description": "How many Cruva-pushed ads (registry rows) this campaign contains — all-time, not date-scoped."
                              },
                              "spend": {
                                "type": "number",
                                "description": "Summed over the date range. `purchase_value` is Meta-attributed (Pixel/CAPI); TikTok Shop sales don't appear here."
                              },
                              "impressions": {
                                "type": "number",
                                "description": "Summed over the date range. `purchase_value` is Meta-attributed (Pixel/CAPI); TikTok Shop sales don't appear here."
                              },
                              "clicks": {
                                "type": "number",
                                "description": "Summed over the date range. `purchase_value` is Meta-attributed (Pixel/CAPI); TikTok Shop sales don't appear here."
                              },
                              "purchases": {
                                "type": "number",
                                "description": "Summed over the date range. `purchase_value` is Meta-attributed (Pixel/CAPI); TikTok Shop sales don't appear here."
                              },
                              "purchase_value": {
                                "type": "number",
                                "description": "Summed over the date range. `purchase_value` is Meta-attributed (Pixel/CAPI); TikTok Shop sales don't appear here."
                              },
                              "ctr": {
                                "type": "number",
                                "description": "`clicks / impressions` over the window (a fraction, e.g. `0.0152` = 1.52%)."
                              },
                              "roas": {
                                "type": "number",
                                "description": "`purchase_value / spend` (`0` if no spend)."
                              },
                              "cost_per_purchase": {
                                "type": "number",
                                "description": "`spend / purchases` (`0` if no purchases)."
                              }
                            }
                          }
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total campaigns with activity in the window (within the filters)."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "campaigns": [
                          {
                            "campaign_id": "120210000000000001",
                            "campaign_name": "Creator ads - July",
                            "pushed_ads": 34,
                            "spend": 8241.55,
                            "impressions": 1204551,
                            "clicks": 18342,
                            "purchases": 411,
                            "purchase_value": 24518.2,
                            "ctr": 0.0152,
                            "roas": 2.97,
                            "cost_per_purchase": 20.05
                          },
                          {
                            "campaign_id": "120210000000000002",
                            "campaign_name": null,
                            "pushed_ads": 0,
                            "spend": 312.09,
                            "impressions": 60112,
                            "clicks": 702,
                            "purchases": 9,
                            "purchase_value": 401.33,
                            "ctr": 0.0117,
                            "roas": 1.29,
                            "cost_per_purchase": 34.68
                          }
                        ],
                        "total_count": 6,
                        "page": 1,
                        "page_size": 10,
                        "sort_by": "spend",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "a date range is required; missing or malformed shop header",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "a date range is required",
                    "value": {
                      "error": "Missing date_range (from/to)"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/meta/adsets": {
      "post": {
        "operationId": "metaAdsets",
        "summary": "Meta Ads - List Ad Sets",
        "description": "List the Meta ad sets containing ads pushed from Cruva, with metrics aggregated over a date range and a campaign breadcrumb on every row. **Cruva-pushed ads only** (see the [section overview](https://cruva.com/docs/api#meta-ads-about)). Filter by `campaign_id` (from [Meta Ads - List Campaigns](https://cruva.com/docs/api#meta-campaigns)) to see one campaign's ad sets; pass an `adset_id` to [Meta Ads - List Ads](https://cruva.com/docs/api#meta-ads) for the ads inside.",
        "tags": [
          "Meta Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#meta-adsets"
        },
        "security": [
          {
            "apiKey": [
              "POST /meta/adsets"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Same conventions as [Meta Ads - List Campaigns](https://cruva.com/docs/api#meta-campaigns): snake/camel keys, `spend` fallback sort, no live Meta calls, and `\"format\": \"csv\"` for a presigned CSV export.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` metrics window."
                      },
                      "to": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` metrics window."
                      }
                    },
                    "description": "required",
                    "required": [
                      "from",
                      "to"
                    ]
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict to one or more Meta campaigns."
                  },
                  "adset_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Meta ad set id(s) to look up."
                  },
                  "program_id": {
                    "type": "string",
                    "description": "*(optional)* Only count ads attributed to this Meta Ads program."
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  },
                  "campaign_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Restrict to one or more Meta campaigns."
                  }
                },
                "required": [
                  "date_range"
                ]
              },
              "example": {
                "date_range": {
                  "from": "2026-07-01",
                  "to": "2026-07-31"
                },
                "campaign_id": "120210000000000001",
                "adset_ids": [
                  "120210000000000101"
                ],
                "program_id": "66b1f0aa77cc00112233dd01",
                "page": 1,
                "page_size": 10,
                "sort_by": "spend",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "adsets": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "adset_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Meta ad set id and its push-time name (`null` name when never pushed into from Cruva)."
                              },
                              "adset_name": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Meta ad set id and its push-time name (`null` name when never pushed into from Cruva)."
                              },
                              "campaign_id": {
                                "type": "string",
                                "description": "Parent campaign breadcrumb."
                              },
                              "campaign_name": {
                                "type": "string",
                                "description": "Parent campaign breadcrumb."
                              },
                              "pushed_ads": {
                                "type": "number",
                                "description": "Cruva-pushed ads in this ad set (all-time registry count)."
                              },
                              "spend": {
                                "type": "number"
                              },
                              "impressions": {
                                "type": "number"
                              },
                              "clicks": {
                                "type": "number"
                              },
                              "purchases": {
                                "type": "number"
                              },
                              "purchase_value": {
                                "type": "number"
                              },
                              "ctr": {
                                "type": "number"
                              },
                              "roas": {
                                "type": "number"
                              },
                              "cost_per_purchase": {
                                "type": "number"
                              }
                            }
                          }
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total ad sets with activity in the window (within the filters)."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "adsets": [
                          {
                            "adset_id": "120210000000000101",
                            "adset_name": "July creators",
                            "campaign_id": "120210000000000001",
                            "campaign_name": "Creator ads - July",
                            "pushed_ads": 22,
                            "spend": 5120.33,
                            "impressions": 733208,
                            "clicks": 11250,
                            "purchases": 268,
                            "purchase_value": 16821.9,
                            "ctr": 0.0153,
                            "roas": 3.28,
                            "cost_per_purchase": 19.11
                          }
                        ],
                        "total_count": 3,
                        "page": 1,
                        "page_size": 10,
                        "sort_by": "spend",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/meta/ads": {
      "post": {
        "operationId": "metaAds",
        "summary": "Meta Ads - List Ads",
        "description": "List individual Meta ads (ad creatives) with metrics over a date range. These are the **partnership ads created by pushing TikTok videos from Cruva** — each row maps back to its source TikTok video and creator. Not a mirror of your whole Meta Ads account (see the [section overview](https://cruva.com/docs/api#meta-ads-about)).",
        "tags": [
          "Meta Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#meta-ads"
        },
        "security": [
          {
            "apiKey": [
              "POST /meta/ads"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Same conventions as the other Meta Ads endpoints: snake/camel keys, `spend` fallback sort, `\"format\": \"csv\"` for a presigned CSV export. `handle` matches the push-time creator handle exactly (leading `@` ignored).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` metrics window."
                      },
                      "to": {
                        "type": "string",
                        "format": "date",
                        "description": "**Required.** `YYYY-MM-DD` metrics window."
                      }
                    },
                    "description": "required",
                    "required": [
                      "from",
                      "to"
                    ]
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict to one campaign and/or one ad set (arrays accepted via `campaign_ids` / `adset_ids`)."
                  },
                  "adset_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict to one campaign and/or one ad set (arrays accepted via `campaign_ids` / `adset_ids`)."
                  },
                  "program_id": {
                    "type": "string",
                    "description": "*(optional)* Only ads attributed to this Meta Ads program."
                  },
                  "handle": {
                    "type": "string",
                    "description": "*(optional)* Creator TikTok handle — only that creator's ads."
                  },
                  "video_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Source TikTok video id(s) — every ad created from those videos."
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `spend` / `DESC`."
                  }
                },
                "required": [
                  "date_range"
                ]
              },
              "example": {
                "date_range": {
                  "from": "2026-07-01",
                  "to": "2026-07-31"
                },
                "campaign_id": "120210000000000001",
                "adset_id": "120210000000000101",
                "program_id": "66b1f0aa77cc00112233dd01",
                "handle": "example_creator",
                "video_ids": [
                  "7600000000000000111"
                ],
                "page": 1,
                "page_size": 10,
                "sort_by": "spend",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "ads": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "ad_id": {
                                "type": "string",
                                "description": "Meta ad id."
                              },
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Container breadcrumbs; names are push-time stamps (`null` when unknown)."
                              },
                              "campaign_name": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Container breadcrumbs; names are push-time stamps (`null` when unknown)."
                              },
                              "adset_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Container breadcrumbs; names are push-time stamps (`null` when unknown)."
                              },
                              "adset_name": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Container breadcrumbs; names are push-time stamps (`null` when unknown)."
                              },
                              "program_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Meta Ads program the push was attributed to, or `null`."
                              },
                              "handle": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Creator's TikTok handle from the push registry (falls back to the content row), or `null`."
                              },
                              "video_id": {
                                "type": "string",
                                "description": "The source TikTok video and its **organic** stats (not ad metrics)."
                              },
                              "title": {
                                "type": "string",
                                "description": "The source TikTok video and its **organic** stats (not ad metrics)."
                              },
                              "view_count": {
                                "type": "integer",
                                "description": "The source TikTok video and its **organic** stats (not ad metrics)."
                              },
                              "like_count": {
                                "type": "integer",
                                "description": "The source TikTok video and its **organic** stats (not ad metrics)."
                              },
                              "comment_count": {
                                "type": "integer",
                                "description": "The source TikTok video and its **organic** stats (not ad metrics)."
                              },
                              "post_time": {
                                "type": "string",
                                "description": "The source TikTok video and its **organic** stats (not ad metrics)."
                              },
                              "pushed_time": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "When the ad was created through Cruva, or `null`."
                              },
                              "video_link": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "TikTok URL of the source video, or `null` when handle/video are unknown."
                              },
                              "spend": {
                                "type": "number"
                              },
                              "impressions": {
                                "type": "number"
                              },
                              "clicks": {
                                "type": "number"
                              },
                              "purchases": {
                                "type": "number"
                              },
                              "purchase_value": {
                                "type": "number"
                              },
                              "ctr": {
                                "type": "number"
                              },
                              "roas": {
                                "type": "number"
                              },
                              "cost_per_purchase": {
                                "type": "number"
                              }
                            }
                          }
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total ads with activity in the window (within the filters)."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "ads": [
                          {
                            "ad_id": "120210000000001001",
                            "campaign_id": "120210000000000001",
                            "campaign_name": "Creator ads - July",
                            "adset_id": "120210000000000101",
                            "adset_name": "July creators",
                            "program_id": "66b1f0aa77cc00112233dd01",
                            "handle": "example_creator",
                            "video_id": "7600000000000000111",
                            "title": "5 AMAZING smells in this package!",
                            "view_count": 19888,
                            "like_count": 129,
                            "comment_count": 8,
                            "post_time": "2026-05-31 06:33:49",
                            "pushed_time": "2026-07-02 14:20:11.532000",
                            "video_link": "https://www.tiktok.com/@example_creator/video/7600000000000000111",
                            "spend": 812.4,
                            "impressions": 118322,
                            "clicks": 1922,
                            "purchases": 44,
                            "purchase_value": 2610.75,
                            "ctr": 0.0162,
                            "roas": 3.21,
                            "cost_per_purchase": 18.46
                          }
                        ],
                        "total_count": 34,
                        "page": 1,
                        "page_size": 10,
                        "sort_by": "spend",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/meta/programs": {
      "post": {
        "operationId": "metaPrograms",
        "summary": "Meta Ads - List Programs",
        "description": "List the shop's Meta Ads creator programs — joinable offers whose members license their TikTok content for Meta partnership ads — with member counts, ad performance, and creator earnings. To list a program's members, pass its `program_id` to [Meta Ads - List Program Creators](https://cruva.com/docs/api#meta-program-creators).",
        "tags": [
          "Meta Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#meta-programs"
        },
        "security": [
          {
            "apiKey": [
              "POST /meta/programs"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "`spend`/`sales` cover only the program's **Cruva-pushed** Meta ads. Member counts and earnings are always lifetime — `date_range` scopes just the ad-performance rollup. Add `\"format\": \"csv\"` for a presigned CSV export.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "statuses": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Subset of `active`, `paused`, `archived`. Defaults to `active` + `paused` (archived = deleted programs, kept for history)."
                  },
                  "date_range": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string",
                        "format": "date",
                        "description": "*(optional)* `YYYY-MM-DD` window for the spend/sales rollup. Omit for all-time."
                      },
                      "to": {
                        "type": "string",
                        "format": "date",
                        "description": "*(optional)* `YYYY-MM-DD` window for the spend/sales rollup. Omit for all-time."
                      }
                    },
                    "description": "optional; scopes ONLY the spend/sales rollup (all-time when omitted)"
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `created_at` / `DESC`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `created_at` / `DESC`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `created_at` / `DESC`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `created_at` / `DESC`."
                  }
                }
              },
              "example": {
                "statuses": [
                  "active",
                  "paused"
                ],
                "date_range": {
                  "from": "2026-07-01",
                  "to": "2026-07-31"
                },
                "page": 1,
                "page_size": 10,
                "sort_by": "created_at",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "programs": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "program_id": {
                                "type": "string",
                                "description": "Program id — pass to [Meta Ads - List Program Creators](https://cruva.com/docs/api#meta-program-creators) or as `program_id` on the ads endpoints."
                              },
                              "name": {
                                "type": "string"
                              },
                              "description": {
                                "type": "string"
                              },
                              "short_id": {
                                "type": "string",
                                "description": "The public join link creators use (hosted on Cruva Creators)."
                              },
                              "join_url": {
                                "type": "string",
                                "description": "The public join link creators use (hosted on Cruva Creators)."
                              },
                              "status": {
                                "type": "string",
                                "description": "`active` (join link open), `paused` (link closed, everything else unaffected), or `archived` (deleted)."
                              },
                              "approval_mode": {
                                "type": "string",
                                "description": "`manual` — joining creators wait for brand approval; `auto` — approved immediately."
                              },
                              "cadence": {
                                "type": "string",
                                "description": "Payout trigger: `daily`, `weekly`, `biweekly`, or `monthly`. Payouts are queued on this schedule and only sent after brand approval."
                              },
                              "commission_rules": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "type": {
                                      "type": "string"
                                    },
                                    "pct": {
                                      "type": "number"
                                    },
                                    "amount_cents": {
                                      "type": "number"
                                    }
                                  }
                                },
                                "description": "How members earn. `type` is one of `gmv_pct` (% of Meta-attributed sales), `flat_per_order`, `flat_per_submission`, `flat_per_creator` (one-time on join), `meta_ad_performance` (% of ad spend). Percentage rules carry `pct`; flat rules carry `amount_cents`."
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "last_payout_at": {
                                "type": "string"
                              },
                              "members_approved": {
                                "type": "number",
                                "description": "Live membership counts."
                              },
                              "members_pending": {
                                "type": "number",
                                "description": "Live membership counts."
                              },
                              "spend": {
                                "type": "number",
                                "description": "Ad performance of the program's Cruva-pushed Meta ads (all-time, or the requested `date_range`). `sales` is Meta-attributed purchase value (Pixel/CAPI)."
                              },
                              "sales": {
                                "type": "number",
                                "description": "Ad performance of the program's Cruva-pushed Meta ads (all-time, or the requested `date_range`). `sales` is Meta-attributed purchase value (Pixel/CAPI)."
                              },
                              "roas": {
                                "type": "number",
                                "description": "Ad performance of the program's Cruva-pushed Meta ads (all-time, or the requested `date_range`). `sales` is Meta-attributed purchase value (Pixel/CAPI)."
                              },
                              "earnings_paid": {
                                "type": "number",
                                "description": "Creator payouts from the program's ledger: total paid out, and total currently pending brand approval."
                              },
                              "earnings_pending": {
                                "type": "number",
                                "description": "Creator payouts from the program's ledger: total paid out, and total currently pending brand approval."
                              }
                            }
                          }
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Programs matching the status filter."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "programs": [
                          {
                            "program_id": "66b1f0aa77cc00112233dd01",
                            "name": "Core Creators",
                            "description": "Our main creator program.",
                            "short_id": "a1b2c3d4",
                            "join_url": "https://creators.cruva.com/p/a1b2c3d4",
                            "status": "active",
                            "approval_mode": "manual",
                            "cadence": "biweekly",
                            "commission_rules": [
                              {
                                "type": "gmv_pct",
                                "pct": 10
                              },
                              {
                                "type": "flat_per_creator",
                                "amount_cents": 5000
                              }
                            ],
                            "created_at": "2026-06-12T18:04:11.201000",
                            "last_payout_at": "2026-08-01T09:00:00",
                            "members_approved": 48,
                            "members_pending": 6,
                            "spend": 8241.55,
                            "sales": 24518.2,
                            "roas": 2.97,
                            "earnings_paid": 2451.82,
                            "earnings_pending": 310.44
                          }
                        ],
                        "total_count": 2,
                        "page": 1,
                        "page_size": 10,
                        "sort_by": "created_at",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/meta/programs/creators": {
      "post": {
        "operationId": "metaProgramCreators",
        "summary": "Meta Ads - List Program Creators",
        "description": "List the creators inside the shop's Meta Ads programs — membership status, commission terms, lifetime paid earnings, and how many Cruva-pushed partnership ads run each creator's content. Scope to one program with `program_id` (from [Meta Ads - List Programs](https://cruva.com/docs/api#meta-programs)), or omit it for all programs.",
        "tags": [
          "Meta Ads"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#meta-program-creators"
        },
        "security": [
          {
            "apiKey": [
              "POST /meta/programs/creators"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "A creator can be in at most **one program per brand** at a time, so shop-wide listings have one row per creator. Live Meta **whitelisting status is not included** — it requires per-creator Graph API calls; check it on the dashboard's program Creators tab. Add `\"format\": \"csv\"` for a presigned CSV export.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "program_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict to one program's members."
                  },
                  "statuses": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Subset of `pending`, `approved`, `rejected`, `removed`. Defaults to `pending` + `approved`."
                  },
                  "handle": {
                    "type": "string",
                    "description": "*(optional)* Case-insensitive substring match on the creator's TikTok handle."
                  },
                  "page": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `joined_at` / `DESC` (nulls sort last)."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `joined_at` / `DESC` (nulls sort last)."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `joined_at` / `DESC` (nulls sort last)."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "*(optional)* Pagination and sorting; defaults `1` / `10` / `joined_at` / `DESC` (nulls sort last)."
                  }
                }
              },
              "example": {
                "program_id": "66b1f0aa77cc00112233dd01",
                "statuses": [
                  "pending",
                  "approved"
                ],
                "handle": "smith",
                "page": 1,
                "page_size": 10,
                "sort_by": "joined_at",
                "sort_direction": "DESC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "creators": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "creator_id": {
                                "type": "string",
                                "description": "Cruva community account id (UUID) of the creator."
                              },
                              "handle": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Creator's TikTok handle, or `null`."
                              },
                              "status": {
                                "type": "string",
                                "description": "Membership status: `pending` (awaiting brand approval), `approved`, `rejected`, or `removed`."
                              },
                              "program_id": {
                                "type": "string",
                                "description": "The program this membership belongs to."
                              },
                              "program_name": {
                                "type": "string",
                                "description": "The program this membership belongs to."
                              },
                              "commission_pct": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "The GMV % snapshotted on the membership, or `null` (older memberships only carry this; see `commission_rules` for the full terms)."
                              },
                              "commission_rules": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "type": {
                                      "type": "string"
                                    },
                                    "pct": {
                                      "type": "number"
                                    }
                                  }
                                },
                                "description": "The program's current commission rules (same shape as [Meta Ads - List Programs](https://cruva.com/docs/api#meta-programs))."
                              },
                              "joined_at": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Membership timestamps (ISO), `approved_at` `null` while pending."
                              },
                              "approved_at": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "Membership timestamps (ISO), `approved_at` `null` while pending."
                              },
                              "earnings_paid": {
                                "type": "number",
                                "description": "Lifetime paid payouts to this creator from this program's ledger."
                              },
                              "ads_count": {
                                "type": "integer",
                                "description": "How many Meta partnership ads run this creator's content — Cruva-pushed ads only, all-time."
                              },
                              "ig_usernames": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Instagram usernames linked on the creator's Cruva account (empty array when none). Live Meta whitelisting status is not included here."
                              }
                            }
                          }
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total memberships matching the filters."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "sort_by": {
                          "type": "string"
                        },
                        "sort_direction": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "creators": [
                          {
                            "creator_id": "3f1c2d9e-8a45-4b6b-9d2c-51e0aa77bb01",
                            "handle": "example_creator",
                            "status": "approved",
                            "program_id": "66b1f0aa77cc00112233dd01",
                            "program_name": "Core Creators",
                            "commission_pct": 10,
                            "commission_rules": [
                              {
                                "type": "gmv_pct",
                                "pct": 10
                              }
                            ],
                            "joined_at": "2026-06-20T15:12:44.100000",
                            "approved_at": "2026-06-21T09:30:02.550000",
                            "earnings_paid": 512.34,
                            "ads_count": 7,
                            "ig_usernames": [
                              "example.creator"
                            ]
                          }
                        ],
                        "total_count": 54,
                        "page": 1,
                        "page_size": 10,
                        "sort_by": "joined_at",
                        "sort_direction": "DESC"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/samples/funnel": {
      "post": {
        "operationId": "samplesFunnel",
        "summary": "Sample Funnel",
        "description": "Aggregate view of a shop's sample requests: how many sit in each status right now, how far the cohort progressed through requested → approved → shipped → delivered → posted, and the median days between each stage.\n\nUse this instead of paging [Sample Request Search](https://cruva.com/docs/api#samples) and tallying rows — it is a single aggregate over the whole matching set, with no pagination and no row cap, so it is both faster and correct where a paged count would truncate. Reach for the search endpoint when you need the individual rows (creator handles, `apply_id`s to act on, or a CSV export).\n\nNote this counts the sample **requests** themselves, one row per request. It is not a per-creator view: a creator with three requests is counted three times.",
        "tags": [
          "Sample Requests"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#samples-funnel"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/samples/funnel"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": false,
          "description": "**`time_field`** picks which timestamp defines the cohort and defaults to `timestamp` (when the sample was requested), so the funnel reads as *\"of the requests submitted in this window, how far did they get\"*. Accepts `timestamp`, `approved`, `shipped`, `delivered`, and `posted` (the underlying column names — `sample_approved`, `sample_shipped`, `sample_received`, `sample_posted` — also work). Anchor on a later milestone to ask a different question: `time_field: \"approved\"` with an August window is *\"of the samples we approved in August, how many got posted\"*.\n\nOmit `time_from`/`time_to` for all time. A non-default `time_field` restricts the cohort to rows that actually carry that timestamp.\n\n**Stage counts are cumulative, not exclusive.** A request counts as having reached a stage if it ever passed through it, so `funnel` counts only ever shrink down the funnel. They are derived from the milestone timestamps *and* the status — a request sitting in `Content Pending` counts as delivered even if its `sample_received` is missing.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "time_field": {
                    "type": "string",
                    "description": "which timestamp defines the cohort (see note)"
                  },
                  "time_from": {
                    "type": "string",
                    "format": "date"
                  },
                  "time_to": {
                    "type": "string",
                    "format": "date",
                    "description": "inclusive of the whole day"
                  },
                  "product_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "or \"product_id\": \"product_id_123\""
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "or \"all_campaigns\": true"
                  },
                  "source": {
                    "type": "string",
                    "description": "\"TC\" or \"Open\""
                  },
                  "include_ignored": {
                    "type": "boolean",
                    "description": "true also counts ignored requests"
                  }
                }
              },
              "example": {
                "time_field": "timestamp",
                "time_from": "2026-08-01",
                "time_to": "2026-08-30",
                "product_ids": [
                  "product_id_123"
                ],
                "campaign_id": "campaign_id_123",
                "source": "TC",
                "include_ignored": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "time_field": {
                          "type": "string"
                        },
                        "time_from": {
                          "type": "string",
                          "format": "date"
                        },
                        "time_to": {
                          "type": "string",
                          "format": "date"
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Requests in the cohort — every request whose `time_field` falls in the window, after the product/campaign/source filters."
                        },
                        "by_status": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "status": {
                                "type": "string"
                              },
                              "count": {
                                "type": "number"
                              },
                              "pct_of_total": {
                                "type": "number",
                                "description": "The status's share of `total_count`."
                              },
                              "is_open": {
                                "type": "boolean",
                                "description": "`true` while the request is still moving (`To Review`, `Ready to Ship`, `Shipped`, `Content Pending`, `Overdue`, …). Ageing fields are present only on these — the age of a `Rejected` row is not a queue anyone is working through."
                              },
                              "avg_age_days": {
                                "type": "number",
                                "description": "Days since the request was submitted, averaged and maxed over the status. A large, old `To Review` queue is a review backlog; a large, old `Content Pending` queue is creators sitting on product. Open statuses only."
                              },
                              "oldest_age_days": {
                                "type": "number",
                                "description": "Days since the request was submitted, averaged and maxed over the status. A large, old `To Review` queue is a review backlog; a large, old `Content Pending` queue is creators sitting on product. Open statuses only."
                              }
                            }
                          },
                          "description": "**Current state**: where each request sits now, ordered by `count` descending. Statuses come from the data, so shops carrying legacy values (`Delivered`, `Content Posted`, `Pending`, `Approved`) will see them here."
                        },
                        "funnel": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "stage": {
                                "type": "string"
                              },
                              "label": {
                                "type": "string"
                              },
                              "count": {
                                "type": "number"
                              },
                              "pct_of_entry": {
                                "type": "number",
                                "description": "The stage's share of the entry stage (`total_count`)."
                              },
                              "conversion_from_previous_pct": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Share of the previous stage that reached this one. `null` on the entry stage."
                              },
                              "dropped_from_previous": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Requests that reached the previous stage but not this one. `null` on the entry stage."
                              }
                            }
                          },
                          "description": "**Progression** through `requested` → `approved` → `shipped` → `delivered` → `posted`. Cumulative, so counts never increase down the list."
                        },
                        "timing": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "step": {
                                "type": "string"
                              },
                              "label": {
                                "type": "string"
                              },
                              "median_days": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Median days for that transition, over requests carrying both timestamps. `null` when no request has made the transition. Slow is not the same as leaky — a stage can convert well and still take weeks, so read `timing` alongside `funnel`."
                              }
                            }
                          }
                        },
                        "biggest_bottleneck": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "properties": {
                            "stage": {
                              "type": "string"
                            },
                            "label": {
                              "type": "string"
                            },
                            "dropped": {
                              "type": "number"
                            },
                            "conversion_pct": {
                              "type": "number"
                            }
                          },
                          "description": "The transition losing the largest *share* of the funnel (not the largest absolute count, which would always name the first step). `null` when nothing drops. Note a large drop at `approved` is normal for most shops, which reject or expire the bulk of inbound requests — weigh the later steps and the timings before calling it a problem."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "time_field": "timestamp",
                        "time_from": "2026-08-01",
                        "time_to": "2026-08-30",
                        "total_count": 1608,
                        "by_status": [
                          {
                            "status": "Rejected",
                            "count": 1463,
                            "pct_of_total": 90.98,
                            "is_open": false
                          },
                          {
                            "status": "To Review",
                            "count": 122,
                            "pct_of_total": 7.59,
                            "is_open": true,
                            "avg_age_days": 12.4,
                            "oldest_age_days": 74.2
                          }
                        ],
                        "funnel": [
                          {
                            "stage": "requested",
                            "label": "Requested",
                            "count": 1608,
                            "pct_of_entry": 100,
                            "conversion_from_previous_pct": null,
                            "dropped_from_previous": null
                          },
                          {
                            "stage": "approved",
                            "label": "Approved",
                            "count": 145,
                            "pct_of_entry": 9.02,
                            "conversion_from_previous_pct": 9.02,
                            "dropped_from_previous": 1463
                          },
                          {
                            "stage": "shipped",
                            "label": "Shipped",
                            "count": 145,
                            "pct_of_entry": 9.02,
                            "conversion_from_previous_pct": 100,
                            "dropped_from_previous": 0
                          },
                          {
                            "stage": "delivered",
                            "label": "Delivered",
                            "count": 143,
                            "pct_of_entry": 8.89,
                            "conversion_from_previous_pct": 98.62,
                            "dropped_from_previous": 2
                          },
                          {
                            "stage": "posted",
                            "label": "Posted",
                            "count": 121,
                            "pct_of_entry": 7.53,
                            "conversion_from_previous_pct": 84.62,
                            "dropped_from_previous": 22
                          }
                        ],
                        "timing": [
                          {
                            "step": "request_to_approval",
                            "label": "Requested → Approved",
                            "median_days": 0.38
                          },
                          {
                            "step": "approval_to_shipment",
                            "label": "Approved → Shipped",
                            "median_days": 1
                          },
                          {
                            "step": "shipment_to_delivery",
                            "label": "Shipped → Delivered",
                            "median_days": 3.23
                          },
                          {
                            "step": "delivery_to_post",
                            "label": "Delivered → Posted",
                            "median_days": 3
                          }
                        ],
                        "biggest_bottleneck": {
                          "stage": "approved",
                          "label": "Approved",
                          "dropped": 1463,
                          "conversion_pct": 9.02
                        }
                      }
                    }
                  },
                  "No_matching_requests": {
                    "summary": "No matching requests",
                    "value": {
                      "data": {
                        "time_field": "timestamp",
                        "time_from": "1999-01-01",
                        "time_to": "1999-01-02",
                        "total_count": 0,
                        "by_status": [],
                        "funnel": [],
                        "timing": [],
                        "biggest_bottleneck": null
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/samples/list": {
      "post": {
        "operationId": "samples",
        "summary": "Sample Request Search",
        "description": "Retrieve affiliate sample requests.",
        "tags": [
          "Sample Requests"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#samples"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/samples/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Sort options:** `timestamp`, `med_gmv_revenue`, `med_gmv_revenue_range`, `follower_cnt`, `post_rate`, `pps`, `gpm`, `average_gmv_per_video`, `expire_date`, `shop_gmv`, `engagement`.\nAll filter fields are optional.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "max 100"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "(page * page_size) cannot exceed 1000"
                  },
                  "sort_by": {
                    "type": "string"
                  },
                  "sort_direction": {
                    "type": "string"
                  },
                  "just_count": {
                    "type": "boolean",
                    "description": "if true, returns only total_count (no results, faster response)"
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "sample_status": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "pass [\"ignore\"] to view only ignored requests"
                      },
                      "handle": {
                        "type": "string"
                      },
                      "product_filter": {
                        "type": "string"
                      },
                      "product_ids": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "alternative to product_filter if you want to filter by multiple specific products"
                      },
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "approval_time": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "affiliate_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_followers": {
                            "type": "number"
                          },
                          "max_followers": {
                            "type": "number"
                          }
                        }
                      },
                      "shop_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_video_gmv": {
                            "type": "number"
                          },
                          "max_video_gmv": {
                            "type": "number"
                          },
                          "min_live_gmv": {
                            "type": "number"
                          },
                          "max_live_gmv": {
                            "type": "number"
                          },
                          "min_units_sold": {
                            "type": "number"
                          },
                          "max_units_sold": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  },
                  "prev_worked_with": {
                    "type": "boolean",
                    "description": "true = creator has previously posted/shipped/etc. for this shop"
                  },
                  "expiring_soon": {
                    "type": "boolean",
                    "description": "true = expire_date within next 3 days"
                  },
                  "source": {
                    "type": "string",
                    "description": "\"TC\" or \"Open\""
                  }
                }
              },
              "example": {
                "page_size": 50,
                "page_number": 1,
                "sort_by": "timestamp",
                "sort_direction": "desc",
                "just_count": false,
                "filters": {
                  "sample_status": [
                    "To Review",
                    "Ready to Ship"
                  ],
                  "handle": "example_creator",
                  "product_filter": "product_id_123",
                  "product_ids": [
                    "product_id_123",
                    "product_id_456"
                  ],
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "approval_time": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "affiliate_performance": {
                    "min_gmv": 1000,
                    "max_gmv": 100000,
                    "min_followers": 5000,
                    "max_followers": 500000
                  },
                  "shop_performance": {
                    "min_gmv": 0,
                    "max_gmv": 100000,
                    "min_video_gmv": 0,
                    "max_video_gmv": 100000,
                    "min_live_gmv": 0,
                    "max_live_gmv": 100000,
                    "min_units_sold": 0,
                    "max_units_sold": 10000
                  }
                },
                "prev_worked_with": true,
                "expiring_soon": false,
                "source": "TC"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "shop_id": {
                                "type": "string"
                              },
                              "creator_id": {
                                "type": "string"
                              },
                              "sampled_product": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "timestamp": {
                                "type": "string"
                              },
                              "sample_approved": {
                                "type": "string"
                              },
                              "sample_received": {},
                              "expire_date": {
                                "type": "string"
                              },
                              "source": {
                                "type": "string"
                              },
                              "apply_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "bio": {
                                "type": "string"
                              },
                              "follower_cnt": {
                                "type": "integer"
                              },
                              "post_rate": {
                                "type": "string"
                              },
                              "video_engagement": {
                                "type": "number"
                              },
                              "med_gmv_revenue": {
                                "type": "number",
                                "description": "total GMV earned across the platform in the last 30 days"
                              },
                              "med_gmv_revenue_range": {
                                "type": "number"
                              },
                              "pps": {
                                "type": "number"
                              },
                              "gpm": {
                                "type": "number"
                              },
                              "shop_gmv": {
                                "type": "number"
                              },
                              "average_gmv_per_video": {
                                "type": "number"
                              },
                              "previous_approved": {
                                "type": "boolean",
                                "description": "true if this creator has another active sample with this shop"
                              }
                            }
                          }
                        },
                        "page_number": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "populated on page 1 or when just_count = true"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "shop_id": "your_shop_id_here",
                            "creator_id": "7171717171717171717",
                            "sampled_product": "product_id_123",
                            "status": "To Review",
                            "campaign_id": null,
                            "timestamp": "2025-09-10T01:00:57.815932",
                            "sample_approved": "2025-09-12T14:22:11.000000",
                            "sample_received": null,
                            "expire_date": "2025-10-10T00:00:00.000000",
                            "source": "TC",
                            "apply_id": "9191919191919191919",
                            "handle": "example_creator",
                            "bio": "creator bio text",
                            "follower_cnt": 4413,
                            "post_rate": "N/A",
                            "video_engagement": 0.04,
                            "med_gmv_revenue": 0,
                            "med_gmv_revenue_range": 1,
                            "pps": 0,
                            "gpm": 0,
                            "shop_gmv": 0,
                            "average_gmv_per_video": 0,
                            "previous_approved": false
                          }
                        ],
                        "page_number": 1,
                        "page_size": 50,
                        "total_count": 1,
                        "has_more": false
                      }
                    }
                  },
                  "Count_only_Response_just_count_true": {
                    "summary": "Count-only Response (`just_count: true`)",
                    "value": {
                      "data": {
                        "total_count": 142
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/samples/refundable/list": {
      "post": {
        "operationId": "samplesRefundable",
        "summary": "Refundable Sample Request Search",
        "description": "Retrieve **refundable** sample requests — samples the creator purchases themselves and is refunded for after posting. Unlike regular sample requests there is no request/approval step, so the status set is reduced and each row carries refund fields (`refund_time`, `refund_amount`, `review_expire_time`) plus SKU-level detail (`sku_id`, `sku_desc`) and the offered `commission_rate`.\n\n**`sample_status` — refundable sample statuses:** `Ready to Ship`, `Shipped`, `Content Pending`, `Refunded`, `Canceled`\n\nRefundable samples have no request/approval step, so the status set is reduced compared to regular sample requests.",
        "tags": [
          "Sample Requests"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#samples-refundable"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/samples/refundable/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Sort options:** `timestamp`, `sample_shipped`, `sample_received`, `refund_time`, `refund_amount`, `commission_rate`, `review_expire_time`, `follower_cnt`, `shop_gmv`.\n**`time_field`** selects which timestamp column `date_range` filters on: `timestamp` (when the sample was requested, default), `sample_shipped`, `sample_received`, `refund_time`, or `review_expire_time` — e.g. \"refunded in June\" → `time_field: \"refund_time\"`.\nAll filter fields are optional.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page_size": {
                    "type": "integer",
                    "description": "max 100"
                  },
                  "page_number": {
                    "type": "integer",
                    "description": "(page * page_size) cannot exceed 1000"
                  },
                  "sort_by": {
                    "type": "string"
                  },
                  "sort_direction": {
                    "type": "string"
                  },
                  "time_field": {
                    "type": "string",
                    "description": "which timestamp the date_range filters on (see note)"
                  },
                  "just_count": {
                    "type": "boolean",
                    "description": "if true, returns only total_count (no results, faster response)"
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "sample_status": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "handle": {
                        "type": "string"
                      },
                      "product_filter": {
                        "type": "string"
                      },
                      "product_ids": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "alternative to product_filter for multiple products"
                      },
                      "exclude_product_ids": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "sku_ids": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "date_range": {
                        "type": "object",
                        "properties": {
                          "from": {
                            "type": "string",
                            "format": "date"
                          },
                          "to": {
                            "type": "string",
                            "format": "date"
                          }
                        }
                      },
                      "affiliate_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_followers": {
                            "type": "number"
                          },
                          "max_followers": {
                            "type": "number"
                          }
                        }
                      },
                      "shop_performance": {
                        "type": "object",
                        "properties": {
                          "min_gmv": {
                            "type": "number"
                          },
                          "max_gmv": {
                            "type": "number"
                          },
                          "min_video_gmv": {
                            "type": "number"
                          },
                          "max_video_gmv": {
                            "type": "number"
                          },
                          "min_live_gmv": {
                            "type": "number"
                          },
                          "max_live_gmv": {
                            "type": "number"
                          },
                          "min_units_sold": {
                            "type": "number"
                          },
                          "max_units_sold": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "or \"all_campaigns\": true"
                  }
                }
              },
              "example": {
                "page_size": 50,
                "page_number": 1,
                "sort_by": "timestamp",
                "sort_direction": "desc",
                "time_field": "timestamp",
                "just_count": false,
                "filters": {
                  "sample_status": [
                    "Shipped",
                    "Refunded"
                  ],
                  "handle": "example_creator",
                  "product_filter": "product_id_123",
                  "product_ids": [
                    "product_id_123",
                    "product_id_456"
                  ],
                  "exclude_product_ids": [
                    "product_id_789"
                  ],
                  "sku_ids": [
                    "1729382056",
                    "1729382057"
                  ],
                  "date_range": {
                    "from": "2026-04-01",
                    "to": "2026-04-07"
                  },
                  "affiliate_performance": {
                    "min_gmv": 1000,
                    "max_gmv": 100000,
                    "min_followers": 5000,
                    "max_followers": 500000
                  },
                  "shop_performance": {
                    "min_gmv": 0,
                    "max_gmv": 100000,
                    "min_video_gmv": 0,
                    "max_video_gmv": 100000,
                    "min_live_gmv": 0,
                    "max_live_gmv": 100000,
                    "min_units_sold": 0,
                    "max_units_sold": 10000
                  }
                },
                "campaign_id": "campaign_id_123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "shop_id": {
                                "type": "string"
                              },
                              "creator_id": {
                                "type": "string"
                              },
                              "sampled_product": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "campaign_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "timestamp": {
                                "type": "string"
                              },
                              "apply_id": {
                                "type": "string"
                              },
                              "sku_id": {
                                "type": "string"
                              },
                              "sku_desc": {
                                "type": "string"
                              },
                              "commission_rate": {
                                "type": "number",
                                "description": "basis points (1500 = 15%)"
                              },
                              "sample_shipped": {
                                "type": "string"
                              },
                              "sample_received": {
                                "type": "string"
                              },
                              "refund_time": {
                                "type": "string"
                              },
                              "refund_amount": {
                                "type": "number"
                              },
                              "review_expire_time": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "bio": {
                                "type": "string"
                              },
                              "follower_cnt": {
                                "type": "integer"
                              },
                              "med_gmv_revenue": {
                                "type": "number",
                                "description": "total GMV earned across the platform in the last 30 days"
                              },
                              "med_gmv_revenue_range": {
                                "type": "number"
                              },
                              "shop_gmv": {
                                "type": "number"
                              },
                              "product_info": {
                                "type": "object",
                                "properties": {
                                  "product_id": {
                                    "type": "string"
                                  },
                                  "product_name": {
                                    "type": "string"
                                  },
                                  "is_open_plan": {
                                    "type": "boolean"
                                  },
                                  "price": {
                                    "type": "number"
                                  },
                                  "units_sold": {
                                    "type": "number"
                                  }
                                }
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "populated on page 1 or when just_count = true"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "shop_id": "your_shop_id_here",
                            "creator_id": "7171717171717171717",
                            "sampled_product": "product_id_123",
                            "status": "Refunded",
                            "campaign_id": null,
                            "timestamp": "2026-06-10T01:00:57.815932",
                            "apply_id": "9191919191919191919",
                            "sku_id": "1729382056",
                            "sku_desc": "Color: Black / Size: M",
                            "commission_rate": 1500,
                            "sample_shipped": "2026-06-12T14:22:11",
                            "sample_received": "2026-06-15T09:10:00",
                            "refund_time": "2026-06-20T18:05:42",
                            "refund_amount": 19.99,
                            "review_expire_time": "2026-07-15T00:00:00",
                            "handle": "example_creator",
                            "bio": "creator bio text",
                            "follower_cnt": 4413,
                            "med_gmv_revenue": 0,
                            "med_gmv_revenue_range": 1,
                            "shop_gmv": 0,
                            "product_info": {
                              "product_id": "product_id_123",
                              "product_name": "Example Product",
                              "is_open_plan": true,
                              "price": 24.99,
                              "units_sold": 1200
                            }
                          }
                        ],
                        "page": 1,
                        "page_size": 50,
                        "total_count": 1,
                        "has_more": false
                      }
                    }
                  },
                  "Count_only_Response_just_count_true": {
                    "summary": "Count-only Response (`just_count: true`)",
                    "value": {
                      "data": {
                        "total_count": 37
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/samples/approve": {
      "post": {
        "operationId": "samplesApprove",
        "summary": "Approve Sample Requests",
        "description": "Approve one or more sample requests by their `apply_id`. You can get these IDs from the **Sample Request Search** endpoint above.",
        "tags": [
          "Sample Requests"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#samples-approve"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/samples/approve"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "apply_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of `apply_id` values from the Sample Request Search response"
                  }
                }
              },
              "example": {
                "apply_ids": [
                  "9191919191919191919",
                  "9191919191919191920"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "success_count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Successfully approved 2 sample requests",
                        "success_count": 2
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/samples/reject": {
      "post": {
        "operationId": "samplesReject",
        "summary": "Reject Sample Requests",
        "description": "Reject one or more sample requests by their `apply_id`. You can get these IDs from the **Sample Request Search** endpoint above.",
        "tags": [
          "Sample Requests"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#samples-reject"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/samples/reject"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "apply_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of `apply_id` values from the Sample Request Search response"
                  }
                }
              },
              "example": {
                "apply_ids": [
                  "9191919191919191919",
                  "9191919191919191920"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "success_count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Successfully rejected 2 sample requests",
                        "success_count": 2
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/samples/ignore": {
      "post": {
        "operationId": "samplesIgnore",
        "summary": "Ignore Sample Requests",
        "description": "Hide one or more sample requests from the review queue without approving or rejecting them — the same as the **Ignore** button on the dashboard's Sample Requests page. Nothing is sent to TikTok or the creator: the request keeps its TikTok status and simply stops showing up in [Sample Request Search](https://cruva.com/docs/api#samples) (unless you filter `sample_status: [\"ignore\"]`) and in the [Sample Request Funnel](https://cruva.com/docs/api#samples-funnel) (unless `include_ignored` is set). Reverse it with [Unignore Sample Requests](https://cruva.com/docs/api#samples-unignore).\n\nOptionally add the creators behind those requests to the shop's **permanently ignored affiliates** list with `perma_ignore_affiliates`, so every future request from them is auto-ignored as well. Use the `creator_id` and `handle` from the matching search rows. This part is only reversible from the dashboard (Sample Requests → Manage Ignored Affiliates); unignoring the requests does not remove the creator from the list.\n\nSupports the `Idempotency-Key` header.",
        "tags": [
          "Sample Requests"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#samples-ignore"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/samples/ignore"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "apply_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of `apply_id` values from the Sample Request Search response."
                  },
                  "perma_ignore_affiliates": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "creator_id": {
                          "type": "string"
                        },
                        "handle": {
                          "type": "string"
                        }
                      }
                    },
                    "description": "*(optional)* Array of `{ creator_id, handle }` objects, both taken from the Sample Request Search rows. Adds each creator to the shop's ignored-affiliates list so their future requests are auto-ignored. Deduplicated by `creator_id`; `creator_oecuid` is accepted as an alias of `creator_id`."
                  }
                }
              },
              "example": {
                "apply_ids": [
                  "9191919191919191919",
                  "9191919191919191920"
                ],
                "perma_ignore_affiliates": [
                  {
                    "creator_id": "7171717171717171717",
                    "handle": "example_creator"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "updated_count": {
                          "type": "integer"
                        },
                        "ignored": {
                          "type": "boolean"
                        },
                        "perma_ignored_creators": {
                          "type": "number",
                          "description": "only present when perma_ignore_affiliates was sent"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Successfully ignored 2 sample requests",
                        "updated_count": 2,
                        "ignored": true,
                        "perma_ignored_creators": 1
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/samples/unignore": {
      "post": {
        "operationId": "samplesUnignore",
        "summary": "Unignore Sample Requests",
        "description": "Restore sample requests previously hidden with [Ignore Sample Requests](https://cruva.com/docs/api#samples-ignore). They return to the queue in whatever status they currently hold. To find them, call [Sample Request Search](https://cruva.com/docs/api#samples) with `sample_status: [\"ignore\"]`.\n\nThis only affects the given requests — a creator on the permanently ignored affiliates list stays there (remove them from the dashboard under Sample Requests → Manage Ignored Affiliates).\n\nSupports the `Idempotency-Key` header.",
        "tags": [
          "Sample Requests"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#samples-unignore"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/samples/unignore"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "apply_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Array of `apply_id` values from the Sample Request Search response (filter with `sample_status: [\"ignore\"]` to list ignored requests)."
                  }
                }
              },
              "example": {
                "apply_ids": [
                  "9191919191919191919",
                  "9191919191919191920"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "updated_count": {
                          "type": "integer"
                        },
                        "ignored": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Successfully unignored 2 sample requests",
                        "updated_count": 2,
                        "ignored": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/message/dm": {
      "post": {
        "operationId": "dm",
        "summary": "Outreach - Send Direct Message",
        "description": "Send a direct message to a creator. Identify the recipient by either `handle` or `conversation_id` — one of the two is required. Only available in the US and UK for now.",
        "tags": [
          "Outreach"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#dm"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/message/dm"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Creator's TikTok handle. Required unless `conversation_id` is supplied. The conversation is created if one doesn't exist yet."
                  },
                  "conversation_id": {
                    "type": "string",
                    "description": "Send into an existing conversation, e.g. one returned by [List Inbox](https://cruva.com/docs/api#inbox). Required unless `handle` is supplied, and takes precedence when both are given. Skips the handle lookup, so it also works for creators who aren't in our affiliates database."
                  },
                  "message": {
                    "type": "string",
                    "description": "The message text to send."
                  }
                }
              },
              "example": {
                "handle": "example_creator",
                "conversation_id": "7451907556216407553",
                "message": "Hello, collab with us!"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean",
                          "description": "`false` if TikTok rejected the send — check `message` for the reason. Note that the endpoint still returns `200` in that case, so branch on this field rather than the status code."
                        },
                        "message_id": {
                          "type": "string",
                          "description": "TikTok's ID for the message just sent."
                        },
                        "message": {
                          "type": "string",
                          "description": "`Success`, or the upstream error reason when `success` is `false` (e.g. an IM quota limit based on your 30-day affiliate GMV)."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "success": true,
                        "message_id": "123456789",
                        "message": "Success"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/message/list": {
      "post": {
        "operationId": "listMessages",
        "summary": "Outreach - List Messages",
        "description": "List the messages exchanged with a creator, most recent first. Results are paginated with an opaque cursor (TikTok requires token-based pagination, not numeric offsets).",
        "tags": [
          "Outreach"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#list-messages"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/message/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "handle": {
                    "type": "string",
                    "description": "Creator's TikTok handle"
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Number of messages to return. Max 20."
                  },
                  "page_token": {
                    "type": "string",
                    "description": "Optional. Omit on the first request. To fetch the next page, pass back the `next_page_token` returned in the previous response. Continue until `has_more` is `false`."
                  }
                }
              },
              "example": {
                "handle": "example_creator",
                "page_size": 20,
                "page_token": "eyJjdXJzb3IiOiIxNzMwOTk..."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        },
                        "message": {
                          "type": "string"
                        },
                        "has_more": {
                          "type": "boolean",
                          "description": "`true` if additional pages are available."
                        },
                        "messages": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "message_id": {
                                "type": "string",
                                "description": "TikTok's unique ID for the message."
                              },
                              "content": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string",
                                "description": "Message type, e.g. `TEXT`, `IMAGE`, `PRODUCT_CARD`, `TARGET_COLLABORATION_CARD`, `FREE_SAMPLE_CARD`, `EMOTICONS`, or `SYSTEM`. Only `TEXT` messages are guaranteed to have a `content` string. TikTok `NOTIFICATION` events are filtered out."
                              },
                              "sender": {
                                "type": "string",
                                "description": "`creator` or `brand`."
                              },
                              "send_time": {
                                "type": "string"
                              }
                            }
                          },
                          "description": "Array of messages for this page, most recent first."
                        },
                        "next_page_token": {
                          "type": "string",
                          "description": "Opaque cursor for the next page. Pass this as `page_token` on the subsequent request. Absent (or empty) once `has_more` is `false`."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "success": true,
                        "message": "success",
                        "has_more": true,
                        "messages": [
                          {
                            "message_id": "7451907556216407553",
                            "content": "",
                            "type": "TARGET_COLLABORATION_CARD",
                            "sender": "brand",
                            "send_time": "Apr 08, 2026 10:20 PM UTC"
                          },
                          {
                            "message_id": "7451907556216407554",
                            "content": "Hi example_creator! Thanks for reaching out about a potential collaboration. Feel free to browse our products and request a sample. We'll review your request shortly!",
                            "type": "TEXT",
                            "sender": "brand",
                            "send_time": "Feb 27, 2026 02:33 PM UTC"
                          },
                          {
                            "message_id": "7451907556216407555",
                            "content": "How can we work together",
                            "type": "TEXT",
                            "sender": "creator",
                            "send_time": "Feb 27, 2026 02:33 PM UTC"
                          }
                        ],
                        "next_page_token": "eyJjdXJzb3IiOiIxNzMwOTk..."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/message/inbox": {
      "post": {
        "operationId": "inbox",
        "summary": "Outreach - List Inbox",
        "description": "List conversations in the shop's message inbox, optionally filtered by status. Results are paginated with an opaque cursor (TikTok requires token-based pagination, not numeric offsets).",
        "tags": [
          "Outreach"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#inbox"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/message/inbox"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "conversation_status": {
                    "type": "string",
                    "description": "One of `ALL`, `UNREPLIED`, `READ`, or `UNREAD`"
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Number of conversations to return. Max 50."
                  },
                  "page_token": {
                    "type": "string",
                    "description": "Optional. Omit on the first request. To fetch the next page, pass back the `next_page_token` returned in the previous response. Continue until `has_more` is `false`."
                  }
                }
              },
              "example": {
                "conversation_status": "UNREPLIED",
                "page_size": 20,
                "page_token": "eyJjdXJzb3IiOiIxNzMwOTk..."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "success": {
                          "type": "boolean"
                        },
                        "conversations": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "conversation_id": {
                                "type": "string",
                                "description": "TikTok's unique ID for the conversation. Pass this to [Send Direct Message](https://cruva.com/docs/api#dm) as `conversation_id` to reply without a handle lookup."
                              },
                              "username": {
                                "type": "string",
                                "description": "The creator's TikTok handle."
                              },
                              "unread_count": {
                                "type": "integer",
                                "description": "Number of messages in the conversation the shop hasn't read yet."
                              }
                            }
                          },
                          "description": "Array of conversations for this page."
                        },
                        "has_more": {
                          "type": "boolean",
                          "description": "`true` if additional pages are available."
                        },
                        "next_page_token": {
                          "type": "string",
                          "description": "Opaque cursor for the next page. Pass this as `page_token` on the subsequent request. Absent (or empty) once `has_more` is `false`."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "success": true,
                        "conversations": [
                          {
                            "conversation_id": "7451907556216407553",
                            "username": "example_creator_1",
                            "unread_count": 2
                          },
                          {
                            "conversation_id": "7451907556216407554",
                            "username": "example_creator_2",
                            "unread_count": 2
                          },
                          {
                            "conversation_id": "7451907556216407555",
                            "username": "example_creator_3",
                            "unread_count": 3
                          },
                          {
                            "conversation_id": "7451907556216407556",
                            "username": "example_creator_4",
                            "unread_count": 1
                          },
                          {
                            "conversation_id": "7451907556216407557",
                            "username": "example_creator_5",
                            "unread_count": 1
                          }
                        ],
                        "has_more": true,
                        "next_page_token": "eyJjdXJzb3IiOiIxNzMwOTk..."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/outreach/logs/list": {
      "post": {
        "operationId": "outreachLogs",
        "summary": "Outreach - List Activity Logs",
        "description": "Search the per-message activity log across **all** of the shop's outreach — DM/invite automations and email campaigns alike. One row per attempted message: creator handle, campaign, channel, timestamp, and the error when it failed. `campaign_id` is optional by design: \"which campaign messaged @handle?\" is a `handle_search` with no campaign filter.\n\n**Message types (`message_type`):** `Collab Invite` (Target Collab invitation sent by an automation.), `Dm` (Direct message sent by an automation.), `Followup Dm` (Follow-up DM step.), `Email` (Email sent by an email campaign.), `AI Reply` (AI auto-reply.)",
        "tags": [
          "Outreach"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#outreach-logs"
        },
        "security": [
          {
            "apiKey": [
              "POST /outreach/logs/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "optional, default 1"
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "optional, default 25, max 100"
                  },
                  "handle_search": {
                    "type": "string",
                    "description": "Case-insensitive substring match on the creator handle."
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "Restrict to one campaign — an automation `campaign_id` (from `/automations/list`) or an email campaign id. Omit to search across every campaign."
                  },
                  "message_type": {
                    "type": "string",
                    "description": "Filter by channel. One of the values in the reference below."
                  },
                  "status": {
                    "type": "string",
                    "description": "`success` = delivered; `fail` = the row carries an `error_code`."
                  },
                  "error_code": {
                    "type": "string",
                    "description": "Case-insensitive substring match on the error text — e.g. `refused`, `already`."
                  },
                  "date_from": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO-8601 bounds on the log timestamp. Either or both."
                  },
                  "date_to": {
                    "type": "string",
                    "format": "date-time",
                    "description": "ISO-8601 bounds on the log timestamp. Either or both."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "handle_search": "gracewearsit",
                "campaign_id": "6a14aa4f8c93e2105d7bf830",
                "message_type": "Email",
                "status": "fail",
                "error_code": "refused",
                "date_from": "2026-08-01T00:00:00Z",
                "date_to": "2026-08-14T23:59:59Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response 200",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "handle": {
                                "type": "string"
                              },
                              "creator_id": {
                                "type": "string"
                              },
                              "timestamp": {
                                "type": "string"
                              },
                              "campaign_id": {
                                "type": "string"
                              },
                              "campaign_name": {
                                "type": "string"
                              },
                              "message_type": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string",
                                "description": "`success` or `fail` — `fail` rows carry the failure reason in `error_code`."
                              },
                              "error_code": {
                                "type": "string"
                              },
                              "sender_email": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "The mailbox the message was sent from (email campaigns; `null` on rows written before this field existed)."
                              }
                            }
                          },
                          "description": "Log rows, newest first."
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total rows matching the filters."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200": {
                    "summary": "Response 200",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "handle": "gracewearsit",
                            "creator_id": "7495637218804154932",
                            "timestamp": "2026-08-14T11:52:03",
                            "campaign_id": "6a6ba7b231e1010f55846996",
                            "campaign_name": "TEST",
                            "message_type": "Email",
                            "status": "fail",
                            "error_code": "Recipient refused: grace@example.com",
                            "sender_email": "pizza@surgify.io"
                          }
                        ],
                        "total_count": 1,
                        "page": 1,
                        "page_size": 25,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/automations/list": {
      "post": {
        "operationId": "automationsList",
        "summary": "Automations - List Automations",
        "description": "List the outreach automations (campaigns) configured for the shop. Results are paginated and can be filtered by name or campaign id.\n\n**Sortable fields (`sort_by`):** `created_at` (When the automation was created (default).), `last_updated_at` (Most recently edited.), `campaign_name` (Alphabetical by name.), `status` (`active` / `stopped`.), `messages_sent` (Total outreach messages sent.), `messages_remaining` (Estimated audience left to contact.), `replies_received` (Creator replies.), `sample_requests` (Sample requests generated.), `videos_posted` (Videos posted by contacted creators.), `affiliate_gmv` (GMV attributed to the campaign.)\n\nSort by performance to surface your best (or stalled) campaigns — e.g. `affiliate_gmv` desc for top earners, `messages_remaining` desc for the most runway.",
        "tags": [
          "Automations"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#automations-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /automations/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "Optional. Page to fetch. Defaults to `1`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Number of results per page. Defaults to `25`, max `100`."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match against the automation name."
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "Optional. Filter to a specific automation."
                  },
                  "status": {
                    "type": "string",
                    "description": "Optional. Filter by automation state. One of `active` or `stopped`."
                  },
                  "message_type": {
                    "type": "string",
                    "description": "Optional. Filter by outreach mode. One of `dm`, `invite`, or `invite+dm`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "Optional. Sort field — expand **Sortable fields** below. Defaults to `created_at`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "Optional. `asc` or `desc` (default)."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 10,
                "search": "",
                "campaign_id": "",
                "status": "active",
                "message_type": "invite+dm",
                "sort_by": "affiliate_gmv",
                "sort_direction": "desc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "has_more": {
                          "type": "boolean",
                          "description": "`true` if additional pages are available."
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "campaign_id": {
                                "type": "string",
                                "description": "Identifier to pass to `/automations/toggle`."
                              },
                              "shop_id": {
                                "type": "string"
                              },
                              "campaign_name": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "dm_messages": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "message_type": {
                                      "type": "string"
                                    },
                                    "content": {
                                      "type": "string"
                                    },
                                    "followup_time_days": {
                                      "type": "integer"
                                    }
                                  }
                                },
                                "description": "Ordered sequence of messages the DM automation sends. Each item has a `message_type` (e.g. `message`, `image`, `product`, `batch_product`, `batch_image`, `followup`) and a payload that varies by type. Empty when `message_type` is `invite`."
                              },
                              "invite_details": {
                                "type": [
                                  "object",
                                  "null"
                                ],
                                "properties": {
                                  "invite_title": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "invite_message": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "contact_email": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "expire_time": {
                                    "type": [
                                      "number",
                                      "null"
                                    ]
                                  },
                                  "expire_grain": {
                                    "type": [
                                      "string",
                                      "null"
                                    ]
                                  },
                                  "expiration_type": {
                                    "type": "string"
                                  },
                                  "expiration_date": {},
                                  "resolve_conflicts": {
                                    "type": [
                                      "boolean",
                                      "null"
                                    ]
                                  },
                                  "products": {
                                    "type": [
                                      "array",
                                      "null"
                                    ],
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "commission": {
                                          "type": "number"
                                        },
                                        "id": {
                                          "type": "string"
                                        },
                                        "shopAdsCommission": {
                                          "type": "number"
                                        },
                                        "showShopAdsCommission": {
                                          "type": "boolean"
                                        }
                                      }
                                    }
                                  },
                                  "sample_policy": {
                                    "type": [
                                      "object",
                                      "null"
                                    ],
                                    "properties": {
                                      "auto_approve_samples": {
                                        "type": "boolean"
                                      },
                                      "offer_samples": {
                                        "type": "boolean"
                                      }
                                    }
                                  }
                                },
                                "description": "Configuration for invite automations: `invite_title`, `invite_message`, `contact_email`, the expiry (`expire_time`/`expire_grain` for relative, or `expiration_type: \"date\"` + `expiration_date`), `resolve_conflicts`, the `products` offered (with commission rates), and `sample_policy`. `null` when `message_type` is `dm`."
                              },
                              "last_updated_at": {
                                "type": "string"
                              },
                              "message_type": {
                                "type": "string",
                                "description": "Outreach mode. One of `invite`, `dm`, or `invite+dm`."
                              },
                              "messages_sent": {
                                "type": "number"
                              },
                              "messages_remaining": {
                                "type": [
                                  "number",
                                  "null"
                                ],
                                "description": "Estimated audience left to contact. `null` when the estimator hasn't run for this campaign."
                              },
                              "replies_received": {
                                "type": "number"
                              },
                              "sample_requests": {
                                "type": "number"
                              },
                              "videos_posted": {
                                "type": "number"
                              },
                              "affiliate_gmv": {
                                "type": "number"
                              },
                              "outreach_audience": {
                                "type": "string",
                                "description": "Which creators the automation targets (`list`, `new_affiliates`, or `groups`)."
                              },
                              "outreach_filters": {
                                "type": "object",
                                "properties": {},
                                "description": "Filters applied on top of the audience — see the [Creator Filters Reference](https://cruva.com/docs/api#creator-filters-reference)."
                              },
                              "lists": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "For `list` audiences: every uploaded-list title the campaign targets (legacy single-list bots surface as a one-element array)."
                              },
                              "group_id": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "For `groups` audiences: the CRM `group_id` the automation targets. `null` otherwise."
                              },
                              "send_to_all": {
                                "type": "boolean",
                                "description": "`false` means the campaign skips creators already messaged by the shop's other campaigns."
                              },
                              "content_type": {
                                "type": "string",
                                "description": "Preferred creator content type: `any`, `live`, or `video`."
                              },
                              "time_limits": {
                                "type": "object",
                                "properties": {
                                  "from": {
                                    "type": "string"
                                  },
                                  "timezone": {
                                    "type": "string"
                                  },
                                  "to": {
                                    "type": "string"
                                  }
                                },
                                "description": "Daily send window and timezone the automation respects. Empty object when unrestricted."
                              },
                              "daily_message_limits": {
                                "type": "object",
                                "properties": {
                                  "monday": {
                                    "type": "number"
                                  },
                                  "friday": {
                                    "type": "number"
                                  }
                                },
                                "description": "Per-weekday send caps (lowercase weekday keys, 0-3000). Empty object when uncapped."
                              },
                              "daily_limits_timezone": {
                                "type": "string"
                              },
                              "filter_by_entry_date": {
                                "type": "boolean"
                              },
                              "entry_date_threshold": {},
                              "exclude_groups": {
                                "type": "array",
                                "items": {},
                                "description": "Creators to skip: members of these CRM groups (`group_id`), these lists (`list_id`, from `/lists/list`), or creators already targeted by these automations (`campaign_id`)."
                              },
                              "exclude_list_ids": {
                                "type": "array",
                                "items": {
                                  "type": "number"
                                },
                                "description": "Creators to skip: members of these CRM groups (`group_id`), these lists (`list_id`, from `/lists/list`), or creators already targeted by these automations (`campaign_id`)."
                              },
                              "exclude_automations": {
                                "type": "array",
                                "items": {},
                                "description": "Creators to skip: members of these CRM groups (`group_id`), these lists (`list_id`, from `/lists/list`), or creators already targeted by these automations (`campaign_id`)."
                              }
                            }
                          },
                          "description": "Array of automation objects for the current page."
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Total number of automations matching the query."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "has_more": true,
                        "page": 1,
                        "page_size": 10,
                        "results": [
                          {
                            "campaign_id": "7c3a91e4d2f8b56091ad473e",
                            "shop_id": "4d8e1f2a9b3c70516a8d2e4f",
                            "campaign_name": "[Product 2] - Lookalike Audience - MOF",
                            "status": "active",
                            "created_at": "2026-05-11 04:30:32.098000",
                            "dm_messages": [
                              {
                                "message_type": "invite_card"
                              },
                              {
                                "content": "Hi [affiliate_name]! I noticed your amazing content and wanted to reach out about a potential collaboration.",
                                "message_type": "message"
                              },
                              {
                                "content": "Hi [affiliate_name]! Any thoughts?",
                                "followup_time_days": 3,
                                "message_type": "followup"
                              }
                            ],
                            "invite_details": {
                              "invite_title": "Join our affiliate program",
                              "invite_message": "Hi [affiliate_name]! We'd love to have you on board — check out the product and let us know if you'd like a sample.",
                              "contact_email": "brand@example.com",
                              "expire_time": 6,
                              "expire_grain": "weeks",
                              "expiration_type": "relative",
                              "expiration_date": null,
                              "resolve_conflicts": true,
                              "products": [
                                {
                                  "commission": 25,
                                  "id": "191958783233",
                                  "shopAdsCommission": 12,
                                  "showShopAdsCommission": true
                                }
                              ],
                              "sample_policy": {
                                "auto_approve_samples": false,
                                "offer_samples": true
                              }
                            },
                            "last_updated_at": "2026-05-11 04:30:32.498000",
                            "message_type": "invite+dm",
                            "messages_sent": 4823,
                            "messages_remaining": 12047,
                            "replies_received": 612,
                            "sample_requests": 187,
                            "videos_posted": 94,
                            "affiliate_gmv": 28453.71,
                            "outreach_audience": "list",
                            "outreach_filters": {},
                            "lists": [
                              "Summer Creators",
                              "VIPs"
                            ],
                            "group_id": null,
                            "send_to_all": true,
                            "content_type": "any",
                            "time_limits": {
                              "from": "08:00",
                              "timezone": "America/New_York",
                              "to": "22:00"
                            },
                            "daily_message_limits": {
                              "monday": 100,
                              "friday": 50
                            },
                            "daily_limits_timezone": "America/New_York",
                            "filter_by_entry_date": false,
                            "entry_date_threshold": null,
                            "exclude_groups": [],
                            "exclude_list_ids": [
                              1421
                            ],
                            "exclude_automations": []
                          }
                        ],
                        "total_count": 95
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/automations/create": {
      "post": {
        "operationId": "automationsCreate",
        "summary": "Automations - Create Automation",
        "description": "Create a new outreach automation. Returns the new `campaign_id` and the estimated `messages_remaining` for audiences that can be precomputed. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section. Use [affiliate_name] as a placeholder for the affiliate's name in the message and invite message text fields.\n\n**DM message item types (`dm_messages[].type`):** `invite_card` (The Target Collab invite card (only valid on `invite+dm` automations). No other payload.), `message` (Plain text message. Payload: `content` — supports the `[affiliate_name]` placeholder.), `product` (A single product card. Payload: `product_id`.), `image` (An image message. Payload: `image` (image key).), `batch_product` (A multi-product card. Payload: `products` (array of product ids), optional `title`.), `batch_image` (A multi-image message. Payload: `image`, optional `title`.), `message (with a brief link)` (To send a [Creator Brief](#briefs-create), just paste its `link` into a regular `message` step's content.), `followup` (Sent only if no reply after `followup_time_days` (integer ≥ 1, default 3 — must be unique across follow-ups). Payload: `content`, optional `followup_message_type` (any non-followup type; defaults to `message`).)\n\nEach step is sent in order; `followup` steps fire only if the creator hasn't replied. Max **5** steps per campaign — after 5 unanswered messages TikTok blocks the sender.\n\n**Invite expiry grains (`invite_details.expire_grain`):** `days`, `weeks`, `months`\n\n**Weekday keys (`daily_message_limits`):** `monday`, `tuesday`, `wednesday`, `thursday`, `friday`, `saturday`, `sunday`",
        "tags": [
          "Automations"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#automations-create"
        },
        "security": [
          {
            "apiKey": [
              "POST /automations/create"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Side effect:** for `outreach_audience` of `new_affiliates` or `list`, the server invokes an audience-size estimator and stores `messages_remaining` on the bot. This step fails soft — the automation is created even if the estimator times out (in that case `messages_remaining` is returned as `null`).\n**Limits:** a shop may have at most **1000** non-archived automations (`403` past the cap), and a `list` audience may combine at most **10** lists.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Display name for the automation."
                  },
                  "message_type": {
                    "type": "string",
                    "description": "Outreach mode. `invite` sends Target Collab invitations only, `dm` sends direct messages only, `invite+dm` combines both (recommended — the invite card rides inside the DM thread)."
                  },
                  "outreach_audience": {
                    "type": "string",
                    "description": "Who to target. `new_affiliates` = the platform-wide creator pool narrowed by `outreach_filters`; `groups` = a saved CRM segment (requires `group_id`); `list` = one or more saved lists (requires `list_ids` — see the [Lists](https://cruva.com/docs/api#lists-create) endpoints)."
                  },
                  "outreach_filters": {
                    "type": "object",
                    "properties": {},
                    "description": "Optional filter object narrowing the `new_affiliates` pool. Full field vocabulary and allowed values in the [Creator Filters Reference](https://cruva.com/docs/api#creator-filters-reference) below."
                  },
                  "list_ids": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "description": "Required for `list` audiences: an array of up to **10** `list_id` values, as returned by `POST /lists/create` and `POST /lists/list`."
                  },
                  "group_id": {
                    "type": "string",
                    "description": "For `groups` audiences: a `group_id` from `/groups/list`."
                  },
                  "invite_details": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string",
                        "description": "max 29 chars"
                      },
                      "message": {
                        "type": "string",
                        "description": "max 500 chars"
                      },
                      "expire_time": {
                        "type": "number"
                      },
                      "expire_grain": {
                        "type": "string",
                        "description": "\"days\" | \"weeks\" | \"months\""
                      },
                      "expire_date": {
                        "type": "string",
                        "format": "date-time",
                        "description": "OR a fixed calendar expiry (wins over expire_time)"
                      },
                      "contact_email": {
                        "type": "string"
                      },
                      "offer_free_samples": {
                        "type": "boolean",
                        "description": "required boolean"
                      },
                      "auto_approve_free_samples": {
                        "type": "boolean",
                        "description": "defaults to false if not provided"
                      },
                      "resolve_conflicts": {
                        "type": "boolean",
                        "description": "defaults to false if not provided"
                      },
                      "products": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "product_id": {
                              "type": "string"
                            },
                            "commission": {
                              "type": "number"
                            },
                            "shop_ads_commission": {
                              "type": "number"
                            }
                          }
                        },
                        "description": "Products offered on the invite. Each entry: `product_id` (string), `commission` (percent, 1-80), optional `shop_ads_commission` (percent, 0.01-80)."
                      }
                    },
                    "description": "Required when `message_type` is `invite` or `invite+dm`. Must include `title` (≤29 chars), `message` (≤500 chars), `contact_email`, `offer_free_samples` (explicit boolean), at least one entry in `products`, and an expiry: either **relative** (`expire_time` ≥ 1 + `expire_grain`) or a **fixed date** (`expire_date`, ISO-8601 — takes precedence when both are sent). `auto_approve_free_samples` and `resolve_conflicts` are optional booleans."
                  },
                  "dm_messages": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "content": {
                          "type": "string"
                        },
                        "followup_time_days": {
                          "type": "integer"
                        }
                      }
                    },
                    "description": "Ordered list of DM steps — **required for `dm` / `invite+dm`**. Ignored for pure `invite`. **`invite+dm` enforces a strict sequence:** item `[0]` must be `{ \"type\": \"invite_card\" }` and item `[1]` must be a plain `{ \"type\": \"message\", \"content\": ... }` — an invite card with no message after it is rejected (`400`). Extra messages/images and follow-ups may only come after that pair. Plain `dm` needs at least one non-followup step and never contains an `invite_card`. **Max 5 items per campaign** (including the invite card and follow-ups) — TikTok blocks senders after 5 unanswered messages, so requests past the cap return `400`. Each item is `{ \"type\": ... }` plus a type-specific payload — expand **DM message item types** below. `message`/`followup` content is capped at **2,500 characters**. Follow-up delays must be unique integers ≥ 1. Server assigns each step a UUID."
                  },
                  "status": {
                    "type": "string",
                    "description": "Initial status. One of `active` or `stopped`. Defaults to `stopped` so you can review before launch."
                  },
                  "send_to_all": {
                    "type": "boolean",
                    "description": "Default `true` — message every matching creator. Set `false` to skip creators already messaged by any of this shop's other campaigns (cross-campaign dedupe)."
                  },
                  "content_type": {
                    "type": "string",
                    "description": "Preferred creator content type for invites: `any` (default), `live` (shoppable LIVE), or `video` (shoppable video)."
                  },
                  "time_limits": {
                    "type": "object",
                    "properties": {
                      "from": {
                        "type": "string"
                      },
                      "to": {
                        "type": "string"
                      },
                      "timezone": {
                        "type": "string"
                      }
                    },
                    "description": "Daily send window: `from`/`to` as 24-hour `HH:MM` strings plus an IANA `timezone` (e.g. `America/New_York`). Always pass the timezone — without it the times are interpreted as UTC. Omit the object entirely for round-the-clock sending."
                  },
                  "daily_message_limits": {
                    "type": "object",
                    "properties": {
                      "monday": {
                        "type": "number"
                      },
                      "friday": {
                        "type": "number"
                      }
                    },
                    "description": "Per-weekday send caps. Keys are lowercase weekday names (`monday` … `sunday`), values are integers **0-3000**. A missing day is uncapped; `0` pauses that day entirely."
                  },
                  "daily_limits_timezone": {
                    "type": "string",
                    "description": "IANA timezone whose midnight resets the daily caps."
                  },
                  "filter_by_entry_date": {
                    "type": "boolean",
                    "description": "When `filter_by_entry_date` is `true`, only creators whose audience entry date passes `entry_date_threshold` (ISO-8601) are messaged."
                  },
                  "entry_date_threshold": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When `filter_by_entry_date` is `true`, only creators whose audience entry date passes `entry_date_threshold` (ISO-8601) are messaged."
                  },
                  "exclude_groups": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Creators to skip: members of these CRM groups (`group_id`), these lists (`list_id`, from `/lists/list`), or creators already targeted by these automations (`campaign_id`)."
                  },
                  "exclude_list_ids": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "description": "*(optional)* Creators to skip: members of these CRM groups (`group_id`), these lists (`list_id`, from `/lists/list`), or creators already targeted by these automations (`campaign_id`)."
                  },
                  "exclude_automations": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Creators to skip: members of these CRM groups (`group_id`), these lists (`list_id`, from `/lists/list`), or creators already targeted by these automations (`campaign_id`)."
                  }
                }
              },
              "example": {
                "title": "Summer outreach",
                "message_type": "invite+dm",
                "outreach_audience": "new_affiliates",
                "outreach_filters": {},
                "list_ids": [
                  1421,
                  1508
                ],
                "group_id": "6a15c8b29f4d1e7350a8c742",
                "invite_details": {
                  "title": "Try our product!",
                  "message": "Hey [affiliate_name], love your content...",
                  "expire_time": 6,
                  "expire_grain": "weeks",
                  "expire_date": "2026-09-01T00:00:00Z",
                  "contact_email": "brand@example.com",
                  "offer_free_samples": true,
                  "auto_approve_free_samples": false,
                  "resolve_conflicts": true,
                  "products": [
                    {
                      "product_id": "1800291847362058192",
                      "commission": 15,
                      "shop_ads_commission": 5
                    }
                  ]
                },
                "dm_messages": [
                  {
                    "type": "invite_card"
                  },
                  {
                    "type": "message",
                    "content": "Hi [affiliate_name]!"
                  },
                  {
                    "type": "followup",
                    "content": "Any thoughts?",
                    "followup_time_days": 3
                  }
                ],
                "status": "stopped",
                "send_to_all": true,
                "content_type": "any",
                "time_limits": {
                  "from": "09:00",
                  "to": "20:00",
                  "timezone": "America/New_York"
                },
                "daily_message_limits": {
                  "monday": 100,
                  "friday": 50
                },
                "daily_limits_timezone": "America/New_York",
                "filter_by_entry_date": false,
                "entry_date_threshold": "2026-06-01T00:00:00Z",
                "exclude_groups": [
                  "6a15c8b29f4d1e7350a8c742"
                ],
                "exclude_list_ids": [
                  1421
                ],
                "exclude_automations": [
                  "7c3a91e4d2f8b56091ad473e"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string",
                          "description": "Identifier of the new automation. Pass this to `/automations/toggle` or `/automations/delete`."
                        },
                        "status": {
                          "type": "string"
                        },
                        "messages_remaining": {
                          "type": [
                            "number",
                            "null"
                          ],
                          "description": "Estimated audience size for `new_affiliates` / `list`. `null` for `groups` or when the estimator failed soft."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "Automation created.",
                        "campaign_id": "6a14aa4f8c93e2105d7bf830",
                        "status": "stopped",
                        "messages_remaining": 3978511
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation error (the specific field is named in the message)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "validation error (the specific field is named in the message)",
                    "value": {
                      "error": "invite_details.contact_email is required"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "1000-bot cap reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "1000-bot cap reached",
                    "value": {
                      "error": "Automation limit reached for this shop"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/senders/list": {
      "get": {
        "operationId": "emailsSendersList",
        "summary": "Email Campaigns - List Sender Emails",
        "description": "List the shop's linked sender emails (the mailboxes email campaigns send from — Gmail, Outlook, SMTP, or custom-domain addresses) and its custom sending domains with their verification status. Only a `verified` domain can have addresses created on it via [Create Custom Sender Email](https://cruva.com/docs/api#emails-senders-create-custom).",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-senders-list"
        },
        "security": [
          {
            "apiKey": [
              "GET /emails/senders/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "responses": {
          "200": {
            "description": "Response 200",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "sender_emails": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "email": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string",
                                "description": "`gmail`, `outlook`, `smtp`, or `ses` (custom domain address — no mailbox behind it)."
                              },
                              "sender_name": {
                                "type": [
                                  "string",
                                  "null"
                                ],
                                "description": "From display name (custom domain addresses only; `null` otherwise)."
                              },
                              "daily_limit": {
                                "type": "number",
                                "description": "Per-mailbox daily cap and today's usage — sending pauses for a mailbox once it hits its cap."
                              },
                              "messages_sent_today": {
                                "type": "number",
                                "description": "Per-mailbox daily cap and today's usage — sending pauses for a mailbox once it hits its cap."
                              },
                              "created_at": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "custom_domains": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "domain": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string",
                                "description": "`pending`, `verified`, or `failed`. Domains are added and DNS-verified in the Cruva dashboard (Outreach > Email Campaigns > Manage Sender Emails > Manage Domains) — that step can't be done via API because it requires publishing DNS records."
                              },
                              "created_at": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200": {
                    "summary": "Response 200",
                    "value": {
                      "data": {
                        "sender_emails": [
                          {
                            "email": "outreach@surgifycreators.com",
                            "type": "ses",
                            "sender_name": "Sam from Surgify",
                            "daily_limit": 60,
                            "messages_sent_today": 14,
                            "created_at": "2026-08-14 09:12:44.183000"
                          },
                          {
                            "email": "brand@gmail.com",
                            "type": "gmail",
                            "sender_name": null,
                            "daily_limit": 60,
                            "messages_sent_today": 0,
                            "created_at": "2026-06-02 17:30:11.902000"
                          }
                        ],
                        "custom_domains": [
                          {
                            "domain": "surgifycreators.com",
                            "status": "verified",
                            "created_at": "2026-08-13 20:01:37.554000"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/senders/create-custom": {
      "post": {
        "operationId": "emailsSendersCreateCustom",
        "summary": "Email Campaigns - Create Custom Sender Email",
        "description": "Create a sender email address on one of the shop's **verified** custom domains — e.g. domain `surgifycreators.com` + `local_part` `outreach` makes `outreach@surgifycreators.com`. No mailbox or credentials needed; the address sends through the verified domain. Calling again for an existing address updates it (e.g. its `sender_name`) without using another plan slot. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-senders-create-custom"
        },
        "security": [
          {
            "apiKey": [
              "POST /emails/senders/create-custom"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Plan limits:** new addresses count against the shop's linked-email allowance (Basic: 1, Scale: 100). Re-creating an existing address is an update, not a new slot.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain": {
                    "type": "string",
                    "description": "A custom domain already linked to the shop with `status: \"verified\"` (see [List Sender Emails](https://cruva.com/docs/api#emails-senders-list)). Unverified or unknown domains are rejected."
                  },
                  "local_part": {
                    "type": "string",
                    "description": "The address name before the `@` — lowercase letters, digits, and `. _ % + -` between alphanumerics."
                  },
                  "sender_name": {
                    "type": "string",
                    "description": "Optional From display name shown in recipients' inboxes. Change it later with [Update Sender Name](https://cruva.com/docs/api#emails-senders-update-name)."
                  }
                }
              },
              "example": {
                "domain": "surgifycreators.com",
                "local_part": "outreach",
                "sender_name": "Sam from Surgify"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "sender_name": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "Sender email created.",
                        "email": "outreach@surgifycreators.com",
                        "sender_name": "Sam from Surgify"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "domain linked but not verified yet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "domain linked but not verified yet",
                    "value": {
                      "error": "Domain 'surgifycreators.com' is not verified yet (status: pending). Publish its DNS records and wait for verification before creating addresses."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "plan's linked-email allowance used up",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "plan's linked-email allowance used up",
                    "value": {
                      "error": "The Basic plan allows up to 1 linked email. Please upgrade to link more."
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "domain not linked to this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "domain not linked to this shop",
                    "value": {
                      "error": "Domain 'surgifycreators.com' is not linked to this shop. Add and verify it in Cruva under Outreach > Email Campaigns > Manage Sender Emails > Manage Domains (requires publishing DNS records)."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/senders/update-sender-name": {
      "post": {
        "operationId": "emailsSendersUpdateName",
        "summary": "Email Campaigns - Update Sender Name",
        "description": "Set or clear the From display name on a **custom domain** sender email (`type: \"ses\"`). Gmail/Outlook/SMTP mailboxes carry their own account name and are rejected with a `400`.",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-senders-update-name"
        },
        "security": [
          {
            "apiKey": [
              "POST /emails/senders/update-sender-name"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "required — from /emails/senders/list"
                  },
                  "sender_name": {
                    "type": "string",
                    "description": "max 100 chars; empty string clears the name"
                  }
                }
              },
              "example": {
                "email": "outreach@surgifycreators.com",
                "sender_name": "Sam from Surgify"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response 200",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "email": {
                          "type": "string"
                        },
                        "sender_name": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200": {
                    "summary": "Response 200",
                    "value": {
                      "data": {
                        "message": "Sender name updated.",
                        "email": "outreach@surgifycreators.com",
                        "sender_name": "Sam from Surgify"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/campaigns/create": {
      "post": {
        "operationId": "emailsCampaignsCreate",
        "summary": "Email Campaigns - Create Email Campaign",
        "description": "Create an email outreach campaign that emails creators from the shop's linked sender emails. Returns the new `campaign_id` and the estimated audience size where it can be precomputed. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section. Use `[affiliate_name]` as a placeholder for the creator's name in `subject` and `email_body`. Only plain email campaigns are creatable here — Target Collab email campaigns require invite machinery owned by the dashboard.",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-campaigns-create"
        },
        "security": [
          {
            "apiKey": [
              "POST /emails/campaigns/create"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Side effect:** for `outreach_audience` of `new_affiliates` or `list`, the server invokes an audience-size estimator and stores `messages_remaining` on the campaign. This step fails soft — the campaign is created even if the estimator times out (then `messages_remaining` is `null`).\n**Limits:** a shop may have at most **1000** non-archived email campaigns (`403` past the cap).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Display name for the campaign."
                  },
                  "subject": {
                    "type": "string",
                    "description": "Email subject line. Supports the `[affiliate_name]` placeholder."
                  },
                  "email_body": {
                    "type": "string",
                    "description": "Email body — HTML supported, max **2 MB**. Supports the `[affiliate_name]` placeholder."
                  },
                  "sender_emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Addresses to send from — every one must already be linked to the shop (`400` names any that aren't; check with [List Sender Emails](https://cruva.com/docs/api#emails-senders-list)). Max **10**. Sending rotates across them and respects each mailbox's own daily limit."
                  },
                  "cc_emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Optional CC recipients added to every email. Max **10**, each a valid address."
                  },
                  "daily_limit": {
                    "type": "number",
                    "description": "Campaign-wide emails/day cap. At most **150 per sender email** (`400` past the cap); defaults to 60 per sender email."
                  },
                  "outreach_audience": {
                    "type": "string",
                    "description": "Who to target — same semantics as `/automations/create`: `new_affiliates` (platform-wide creator pool narrowed by `outreach_filters`; only creators with a known email address receive anything), `groups` (requires `group_id`), or `list` (requires `list_ids`)."
                  },
                  "outreach_filters": {
                    "type": "object",
                    "properties": {},
                    "description": "Optional filter object narrowing the `new_affiliates` pool. Full vocabulary in the [Creator Filters Reference](https://cruva.com/docs/api#creator-filters-reference)."
                  },
                  "list_ids": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "description": "Required for `list` audiences: an array of up to **10** `list_id` values."
                  },
                  "group_id": {
                    "type": "string",
                    "description": "For `groups` audiences: a `group_id` from `/groups/list`."
                  },
                  "status": {
                    "type": "string",
                    "description": "Initial status. `active` starts sending immediately; default `stopped` so you can review before launch."
                  },
                  "send_to_all": {
                    "type": "boolean",
                    "description": "Default `true` — email every matching creator. `false` skips creators already contacted by the shop's other campaigns."
                  },
                  "filter_by_entry_date": {
                    "type": "boolean",
                    "description": "When `filter_by_entry_date` is `true`, only creators whose audience entry date passes `entry_date_threshold` (ISO-8601) are emailed."
                  },
                  "entry_date_threshold": {
                    "type": "string",
                    "format": "date-time",
                    "description": "When `filter_by_entry_date` is `true`, only creators whose audience entry date passes `entry_date_threshold` (ISO-8601) are emailed."
                  },
                  "exclude_groups": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "*(optional)* Creators to skip: members of these CRM groups (`group_id`) or these lists (`list_id`, from `/lists/list`)."
                  },
                  "exclude_list_ids": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "description": "*(optional)* Creators to skip: members of these CRM groups (`group_id`) or these lists (`list_id`, from `/lists/list`)."
                  }
                }
              },
              "example": {
                "title": "Summer email outreach",
                "subject": "Partner with us, [affiliate_name]?",
                "email_body": "<p>Hi [affiliate_name], ...</p>",
                "sender_emails": [
                  "outreach@surgifycreators.com",
                  "brand@gmail.com"
                ],
                "cc_emails": [
                  "manager@brand.com"
                ],
                "daily_limit": 120,
                "outreach_audience": "new_affiliates",
                "outreach_filters": {},
                "list_ids": [
                  1421,
                  1508
                ],
                "group_id": "6a15c8b29f4d1e7350a8c742",
                "status": "stopped",
                "send_to_all": true,
                "filter_by_entry_date": false,
                "entry_date_threshold": "2026-06-01T00:00:00Z",
                "exclude_groups": [
                  "6a15c8b29f4d1e7350a8c742"
                ],
                "exclude_list_ids": [
                  1421
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string",
                          "description": "Identifier of the new email campaign. Pass it to `/emails/campaigns/update`, `/emails/campaigns/toggle`, or `/emails/campaigns/delete`; its per-message send results appear in [List Activity Logs](https://cruva.com/docs/api#outreach-logs)."
                        },
                        "status": {
                          "type": "string"
                        },
                        "messages_remaining": {
                          "type": [
                            "number",
                            "null"
                          ],
                          "description": "Estimated audience size for `new_affiliates` / `list`. `null` for `groups` or when the estimator failed soft."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "Email campaign created.",
                        "campaign_id": "6a6ba7b231e1010f55846996",
                        "status": "stopped",
                        "messages_remaining": 812445
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "a sender address isn't linked to the shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "a sender address isn't linked to the shop",
                    "value": {
                      "error": "sender email(s) not linked to this shop: hello@notlinked.com. List available senders with GET /emails/senders/list."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "1000-campaign cap reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "1000-campaign cap reached",
                    "value": {
                      "error": "Limit reached. You can only create 1000 email campaigns per store."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "email_body over 2 MB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "email_body over 2 MB",
                    "value": {
                      "error": "email_body is too large (max 2 MB)"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/campaigns/list": {
      "post": {
        "operationId": "emailsCampaignsList",
        "summary": "Email Campaigns - List Email Campaigns",
        "description": "List the shop's email campaigns with their full configuration — subject, body preview, sender emails, CC, audience, daily limit — and send stats. Archived campaigns are hidden unless `status: \"archived\"` is passed. Use this to read a campaign's current values before an [update](https://cruva.com/docs/api#emails-campaigns-update).\n\n**Sortable fields (`sort_by`):** `created_at`, `last_updated_at`, `campaign_name`, `status`, `messages_sent`, `messages_remaining`, `email_views`",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-campaigns-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /emails/campaigns/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "optional, default 1"
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "optional, default 25, max 100"
                  },
                  "search": {
                    "type": "string",
                    "description": "optional — substring match on campaign name"
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "optional — exact match on one campaign"
                  },
                  "status": {
                    "type": "string",
                    "description": "Filter by status. Without it, everything **except archived** is returned (matching the dashboard's default view)."
                  },
                  "message_type": {
                    "type": "string",
                    "description": "`email` = plain email campaign; `target_collab_email` = TC + Email campaign (creatable only in the dashboard)."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "optional — see sortable fields below"
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "optional, \"asc\" | \"desc\""
                  },
                  "include_body": {
                    "type": "boolean",
                    "description": "When `true`, each row also carries the full HTML `email_body` (up to 2 MB per campaign — request narrow pages). Every row always includes a tag-stripped 300-char `body_preview`."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "search": "summer",
                "campaign_id": "6a6ba7b231e1010f55846996",
                "status": "active",
                "message_type": "email",
                "sort_by": "created_at",
                "sort_direction": "desc",
                "include_body": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response 200",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "campaign_id": {
                                "type": "string"
                              },
                              "shop_id": {
                                "type": "string"
                              },
                              "campaign_name": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "message_type": {
                                "type": "string"
                              },
                              "subject": {
                                "type": "string"
                              },
                              "body_preview": {
                                "type": "string"
                              },
                              "cc_emails": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "sender_emails": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "The linked addresses this campaign sends from, resolved to email addresses."
                              },
                              "daily_limit": {
                                "type": "number"
                              },
                              "messages_sent_today": {
                                "type": "number"
                              },
                              "outreach_audience": {
                                "type": "string"
                              },
                              "outreach_filters": {
                                "type": "object",
                                "properties": {
                                  "categories": {
                                    "type": "array",
                                    "items": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "lists": {
                                "type": "array",
                                "items": {}
                              },
                              "group_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "send_to_all": {
                                "type": "boolean"
                              },
                              "filter_by_entry_date": {
                                "type": "boolean"
                              },
                              "entry_date_threshold": {},
                              "exclude_groups": {
                                "type": "array",
                                "items": {}
                              },
                              "exclude_list_ids": {
                                "type": "array",
                                "items": {}
                              },
                              "messages_sent": {
                                "type": "number"
                              },
                              "messages_failed": {
                                "type": "number"
                              },
                              "email_views": {
                                "type": "number",
                                "description": "Opens recorded via the tracking pixel."
                              },
                              "messages_remaining": {
                                "type": "number"
                              },
                              "send_error": {
                                "description": "Set (with the raw error) when sending is genuinely broken on the campaign's SMTP/custom-domain sender and the campaign was paused; `null` otherwise. One-off failures appear only in [List Activity Logs](https://cruva.com/docs/api#outreach-logs)."
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "last_updated_at": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200": {
                    "summary": "Response 200",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "campaign_id": "6a6ba7b231e1010f55846996",
                            "shop_id": "695ff965c185d97c5b1b8d10",
                            "campaign_name": "Summer email outreach",
                            "status": "active",
                            "message_type": "email",
                            "subject": "Partner with us, [affiliate_name]?",
                            "body_preview": "Hi [affiliate_name], we love your content and would like to...",
                            "cc_emails": [
                              "manager@brand.com"
                            ],
                            "sender_emails": [
                              "outreach@surgifycreators.com"
                            ],
                            "daily_limit": 120,
                            "messages_sent_today": 37,
                            "outreach_audience": "new_affiliates",
                            "outreach_filters": {
                              "categories": [
                                "Beauty & Personal Care"
                              ]
                            },
                            "lists": [],
                            "group_id": null,
                            "send_to_all": true,
                            "filter_by_entry_date": false,
                            "entry_date_threshold": null,
                            "exclude_groups": [],
                            "exclude_list_ids": [],
                            "messages_sent": 412,
                            "messages_failed": 3,
                            "email_views": 188,
                            "messages_remaining": 812033,
                            "send_error": null,
                            "created_at": "2026-08-10 14:22:37.554000",
                            "last_updated_at": "2026-08-14 09:12:44.183000"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 4,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/campaigns/update": {
      "post": {
        "operationId": "emailsCampaignsUpdate",
        "summary": "Email Campaigns - Update Email Campaign",
        "description": "**Partial update** of an existing email campaign: only the fields present in the request change; everything else keeps its stored value. Same field semantics and validation as [Create Email Campaign](https://cruva.com/docs/api#emails-campaigns-create), and the merged result is re-validated as a whole — e.g. switching the audience to `groups` fails unless a `group_id` is on file or provided. The campaign's type (plain email vs TC + Email) cannot be changed. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-campaigns-update"
        },
        "security": [
          {
            "apiKey": [
              "POST /emails/campaigns/update"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Side effect:** changing any audience field (`outreach_audience`, `outreach_filters`, `list_ids`) re-runs the audience-size estimator (fail-soft) and refreshes `messages_remaining`.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The email campaign to edit (from `/emails/campaigns/list`)."
                  },
                  "title": {
                    "type": "string",
                    "description": "optional — all other fields optional too"
                  },
                  "subject": {
                    "type": "string"
                  },
                  "email_body": {
                    "type": "string"
                  },
                  "sender_emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Replace the **entire** list when provided. Sender addresses must be linked to the shop; if the new sender count lowers the 150-per-sender ceiling below the stored `daily_limit`, the limit is clamped automatically (or pass `daily_limit` explicitly)."
                  },
                  "cc_emails": {
                    "type": "array",
                    "items": {},
                    "description": "Replace the **entire** list when provided. Sender addresses must be linked to the shop; if the new sender count lowers the 150-per-sender ceiling below the stored `daily_limit`, the limit is clamped automatically (or pass `daily_limit` explicitly)."
                  },
                  "daily_limit": {
                    "type": "number"
                  },
                  "outreach_audience": {
                    "type": "string"
                  },
                  "list_ids": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    }
                  },
                  "status": {
                    "type": "string",
                    "description": "Optionally also set `active` / `stopped` in the same call."
                  }
                }
              },
              "example": {
                "campaign_id": "6a6ba7b231e1010f55846996",
                "title": "Summer email outreach v2",
                "subject": "Quick question, [affiliate_name]",
                "email_body": "<p>Hi [affiliate_name], ...</p>",
                "sender_emails": [
                  "outreach@surgifycreators.com"
                ],
                "cc_emails": [],
                "daily_limit": 100,
                "outreach_audience": "list",
                "list_ids": [
                  1421
                ],
                "status": "active"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response 200",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "messages_remaining": {
                          "type": "number"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200": {
                    "summary": "Response 200",
                    "value": {
                      "data": {
                        "message": "Email campaign updated.",
                        "campaign_id": "6a6ba7b231e1010f55846996",
                        "status": "active",
                        "messages_remaining": 4188
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "merged result would be invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "merged result would be invalid",
                    "value": {
                      "error": "campaign would have no group_id (required for 'groups' audience)"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "campaign doesn't exist on this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "campaign doesn't exist on this shop",
                    "value": {
                      "error": "Email campaign not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/campaigns/toggle": {
      "post": {
        "operationId": "emailsCampaignsToggle",
        "summary": "Email Campaigns - Start / Stop",
        "description": "Start (`active`) or stop (`stopped`) an email campaign. Both directions also clear any stale error/pause flags (send errors, permission issues, daily-cap holds), matching the dashboard's start/stop behavior — so a campaign paused by a fixed sender problem restarts cleanly.",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-campaigns-toggle"
        },
        "security": [
          {
            "apiKey": [
              "POST /emails/campaigns/toggle"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "required"
                  },
                  "status": {
                    "type": "string",
                    "description": "required, \"active\" | \"stopped\""
                  }
                }
              },
              "example": {
                "campaign_id": "6a6ba7b231e1010f55846996",
                "status": "active"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response 200",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200": {
                    "summary": "Response 200",
                    "value": {
                      "data": {
                        "message": "Email campaign set to active"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/emails/campaigns/delete": {
      "delete": {
        "operationId": "emailsCampaignsDelete",
        "summary": "Email Campaigns - Delete Email Campaign",
        "description": "Permanently delete an email campaign. **This cannot be undone** — to keep the campaign's stats visible in the dashboard, stop it (or archive it in the dashboard) instead. Its historical send rows remain queryable in [List Activity Logs](https://cruva.com/docs/api#outreach-logs). Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Email Campaigns"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#emails-campaigns-delete"
        },
        "security": [
          {
            "apiKey": [
              "DELETE /emails/campaigns/delete"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "required"
                  }
                }
              },
              "example": {
                "campaign_id": "6a6ba7b231e1010f55846996"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response 200",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_200": {
                    "summary": "Response 200",
                    "value": {
                      "data": {
                        "message": "Email campaign deleted."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/automations/update": {
      "post": {
        "operationId": "automationsUpdate",
        "summary": "Automations - Update Automation",
        "description": "**Partial update** of an existing automation: only the fields present in the request change — everything else keeps its stored value. Accepts the same fields as [Create Automation](https://cruva.com/docs/api#automations-create) (same shapes, same validation), plus `campaign_id`. The merged result is validated as a whole, so an update can never leave an automation in a state Create would have rejected. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Automations"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#automations-update"
        },
        "security": [
          {
            "apiKey": [
              "POST /automations/update"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Whole-state validation:** switching `message_type` to `invite`/`invite+dm` fails with `400` unless complete invite details are on file or provided in the same call; switching to `dm` fails while the stored steps still contain an `invite_card` (send replacement `dm_messages`); switching `outreach_audience` to `groups`/`list` requires the matching `group_id`/`list_ids`.\n**Side effect:** when the audience or its filters change, the audience-size estimator re-runs (fail-soft) and `messages_remaining` is returned.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The automation to edit. Obtain from `/automations/list`."
                  },
                  "title": {
                    "type": "string",
                    "description": "any create field may be included…"
                  },
                  "outreach_filters": {
                    "type": "object",
                    "properties": {
                      "min_gmv": {
                        "type": "number"
                      }
                    },
                    "description": "…only what you send changes"
                  },
                  "invite_details": {
                    "type": "object",
                    "properties": {
                      "contact_email": {
                        "type": "string"
                      }
                    },
                    "description": "Merged **partially**: pass only the subkeys to change (e.g. just `contact_email`). `products` replaces the whole product list when provided (each entry re-validated). Pass `expire_date` to switch to fixed-date expiry, or `expire_time` + `expire_grain` for relative."
                  },
                  "time_limits": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "properties": {},
                    "description": "Pass `{}` (or `null`) to **clear** the send window or the daily caps; pass a full object to change them."
                  },
                  "status": {
                    "type": "string",
                    "description": "Optional. `active` or `stopped` — saves a separate `/automations/toggle` call."
                  },
                  "dm_messages": {
                    "description": "Replaces the **entire** message sequence when provided, re-validated against the final `message_type` — `invite+dm` requires `[0]` = invite_card and `[1]` = plain message, same as create. Max **5** items — TikTok blocks senders after 5 unanswered messages."
                  },
                  "daily_message_limits": {
                    "description": "Pass `{}` (or `null`) to **clear** the send window or the daily caps; pass a full object to change them."
                  }
                }
              },
              "example": {
                "campaign_id": "7c3a91e4d2f8b56091ad473e",
                "title": "Summer outreach v2",
                "outreach_filters": {
                  "min_gmv": 25000
                },
                "invite_details": {
                  "contact_email": "partnerships@example.com"
                },
                "time_limits": {},
                "status": "stopped"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "messages_remaining": {
                          "type": [
                            "number",
                            "null"
                          ],
                          "description": "Present only when the audience changed: the re-estimated audience size (`null` if the estimator failed soft)."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Automation updated.",
                        "campaign_id": "7c3a91e4d2f8b56091ad473e",
                        "status": "stopped",
                        "messages_remaining": 184203
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation error on the merged result (the field is named)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "validation error on the merged result (the field is named)",
                    "value": {
                      "error": "automation would be missing invite_details field(s): contact_email"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "not found, or not owned by this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "not found, or not owned by this shop",
                    "value": {
                      "error": "Automation not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/automations/toggle": {
      "post": {
        "operationId": "automationsToggle",
        "summary": "Automations - Toggle Automation",
        "description": "Start or stop an existing automation by id.",
        "tags": [
          "Automations"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#automations-toggle"
        },
        "security": [
          {
            "apiKey": [
              "POST /automations/toggle"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The automation to update. Obtain from `/automations/list`."
                  },
                  "status": {
                    "type": "string",
                    "description": "Either `active` (starts the automation) or `stopped` (pauses it)."
                  }
                }
              },
              "example": {
                "campaign_id": "7c3a91e4d2f8b56091ad473e",
                "status": "active"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Automation set to active"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "missing/invalid campaign_id, or status not in {active, stopped}",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "missing/invalid campaign_id, or status not in {active, stopped}",
                    "value": {
                      "error": "status must be one of: active, stopped"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "automation not found, or not owned by this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "automation not found, or not owned by this shop",
                    "value": {
                      "error": "Automation not found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/automations/delete": {
      "delete": {
        "operationId": "automationsDelete",
        "summary": "Automations - Delete Automation",
        "description": "Hard-delete an automation. The record is removed from the database entirely — there is no archive, and the deletion frees a slot against the 1000-bot per-shop limit. The body is parsed with `request.get_json(silent=True)` so a missing or unparseable body returns a clean `400` instead of `415`. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Automations"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#automations-delete"
        },
        "security": [
          {
            "apiKey": [
              "DELETE /automations/delete"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The automation to delete. Obtain from `/automations/list`."
                  }
                }
              },
              "example": {
                "campaign_id": "6a14aa4f8c93e2105d7bf830"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Automation deleted."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "missing or malformed campaign_id (also returned when the body is missing/unparseable)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "missing or malformed campaign_id (also returned when the body is missing/unparseable)",
                    "value": {
                      "error": "Missing campaign_id"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "not found, or not owned by this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "not found, or not owned by this shop",
                    "value": {
                      "error": "Automation not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/automations/categories/list": {
      "get": {
        "operationId": "automationsCategories",
        "summary": "Automations - List Categories",
        "description": "Return the static list of product categories used by outreach-filter UIs. The values returned here are the exact strings accepted by `outreach_filters.categories` on `/automations/create`.",
        "tags": [
          "Automations"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#automations-categories"
        },
        "security": [
          {
            "apiKey": [
              "GET /automations/categories/list"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        "Home Supplies",
                        "Kitchenware",
                        "Textiles & Soft Furnishings",
                        "Household Appliances",
                        "Womenswear & Underwear",
                        "Menswear & Underwear",
                        "Shoes",
                        "Health",
                        "Beauty & Personal Care",
                        "Phones & Electronics",
                        "Computers & Office Equipment",
                        "Pet Supplies",
                        "Sports & Outdoor",
                        "Toys & Hobbies",
                        "Furniture",
                        "Tools & Hardware",
                        "Home Improvement",
                        "Automotive & Motorcycle",
                        "Fashion Accessories",
                        "Food & Beverages",
                        "Books, Magazines & Audio",
                        "Luggage & Bags",
                        "Collectibles",
                        "Jewelry Accessories & Derivatives"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/groups/list": {
      "post": {
        "operationId": "groupsList",
        "summary": "Groups - List Groups",
        "description": "List the CRM groups configured for the shop, paginated and searchable by name.",
        "tags": [
          "Groups"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#groups-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /groups/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "Optional. Page to fetch. Defaults to `1`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Number of results per page. Defaults to `25`, max `100`."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match against the group title."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "search": "vip"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "group_id": {
                                "type": "string",
                                "description": "Identifier to pass to `/automations/create` (with `outreach_audience: \"groups\"`) or to `/groups/delete`."
                              },
                              "name": {
                                "type": "string"
                              },
                              "creator_count": {
                                "type": "integer",
                                "description": "Cached affiliate count for the group's filter. May be `0` if the group has no filters or if the count-resolution step previously failed soft."
                              },
                              "filters": {
                                "type": "object",
                                "properties": {
                                  "min_followers": {
                                    "type": "number"
                                  },
                                  "language": {
                                    "type": "string"
                                  }
                                },
                                "description": "The filter payload that defines this group's audience."
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "last_updated_at": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "group_id": "6a15c8b29f4d1e7350a8c742",
                            "name": "VIP creators",
                            "creator_count": 432,
                            "filters": {
                              "min_followers": 50000,
                              "language": "english"
                            },
                            "created_at": "2026-05-25 14:02:11.000000",
                            "last_updated_at": "2026-05-25 14:02:11.000000"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 12,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/groups/create": {
      "post": {
        "operationId": "groupsCreate",
        "summary": "Groups - Create Group",
        "description": "Create a CRM group from a filter payload. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.\n\n**`statuses` — sample-request status with this shop:** `No Request`, `To Review`, `Ready to Ship`, `Shipped`, `Content Pending`, `Expired`, `Posted`, `Overdue`, `Rejected`, `Canceled`\n\n**`refundable_sample_statuses` — refundable-sample status with this shop:** `Ready to Ship`, `Shipped`, `Content Pending`, `Refunded`, `Not Refunded`, `Canceled`\n\nRefundable samples have no request/approval step, so the status list is reduced. \"Not Refunded\" matches refundable samples that have not (yet) been refunded.\n\n**`sample_source` — how the sample was requested:** `TC` (Target Collab invitation.), `Open` (Open request from the creator.)",
        "tags": [
          "Groups"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#groups-create"
        },
        "security": [
          {
            "apiKey": [
              "POST /groups/create"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Side effect:** when `filters` is non-empty, the server resolves the audience size (`creator_count`) before returning. This step fails soft — the group is created either way, and a `creator_count` of `0` may indicate either an empty result set or a resolver failure.\n**Limits:** a shop may have at most **200** groups. Hitting the cap returns `403`.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Display name for the group. Required, non-empty after trim."
                  },
                  "filters": {
                    "type": "object",
                    "properties": {
                      "min_gmv": {
                        "type": "number",
                        "description": "GMV driven for THIS shop"
                      },
                      "max_gmv": {
                        "type": "number"
                      },
                      "min_videos": {
                        "type": "number",
                        "description": "videos posted for this shop"
                      },
                      "min_days": {
                        "type": "integer",
                        "description": "days since their last post for you"
                      },
                      "max_days": {
                        "type": "integer"
                      },
                      "products": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "engaged with any of these"
                      },
                      "statuses": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "replied": {
                        "type": "boolean"
                      },
                      "min_followers": {
                        "type": "number",
                        "description": "platform-wide stats"
                      },
                      "language": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    },
                    "description": "Filter object — all fields optional and AND-combined; array fields OR-match within the field. Most fields are **scoped to this shop** (the creator's relationship with *your* store); the platform-wide exceptions are called out below. The dashboard requires at least one filter — an unfiltered group resolves to the empty set until edited."
                  }
                }
              },
              "example": {
                "title": "VIP creators",
                "filters": {
                  "min_gmv": 1000,
                  "max_gmv": 100000,
                  "min_videos": 1,
                  "min_days": 0,
                  "max_days": 30,
                  "products": [
                    "1800291847362058192"
                  ],
                  "statuses": [
                    "To Review",
                    "Ready to Ship",
                    "Shipped"
                  ],
                  "replied": true,
                  "min_followers": 10000,
                  "language": [
                    "english"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "group_id": {
                          "type": "string"
                        },
                        "creator_count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "Group created.",
                        "group_id": "6a15c8b29f4d1e7350a8c742",
                        "creator_count": 432
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "title missing/empty, or filters is not an object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "title missing/empty, or filters is not an object",
                    "value": {
                      "error": "title is required"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "200-group cap reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "200-group cap reached",
                    "value": {
                      "error": "Group limit reached for this shop"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/groups/delete": {
      "delete": {
        "operationId": "groupsDelete",
        "summary": "Groups - Delete Group",
        "description": "Hard-delete the group. The body is parsed with `request.get_json(silent=True)` so a missing or unparseable body returns a clean `400` instead of `415`. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.\n\n**Note:** this does not cascade — any automation that references this group via `outreach_audience: \"groups\"` retains its now-dangling `group_id` and will fail to send until you point it at a different group.",
        "tags": [
          "Groups"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#groups-delete"
        },
        "security": [
          {
            "apiKey": [
              "DELETE /groups/delete"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "group_id": {
                    "type": "string",
                    "description": "The group to delete. Obtain from `/groups/list`."
                  }
                }
              },
              "example": {
                "group_id": "6a15c8b29f4d1e7350a8c742"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Group deleted."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "missing or malformed group_id (also returned when the body is missing/unparseable)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "missing or malformed group_id (also returned when the body is missing/unparseable)",
                    "value": {
                      "error": "Missing group_id"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "not found, or not owned by this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "not found, or not owned by this shop",
                    "value": {
                      "error": "Group not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/lists/create": {
      "post": {
        "operationId": "listsCreate",
        "summary": "Lists - Create List",
        "description": "Create a list (or append to an existing one) from an array of creator handles. Handles are normalized, resolved against the creator index, and stored with their resolved creator id. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Lists"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lists-create"
        },
        "security": [
          {
            "apiKey": [
              "POST /lists/create"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Success check:** `added_count` is the number of rows actually written. `0` with a `2xx` means every resolved handle was already in the list. A `400` with `unmatched` means nothing resolved at all.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "number",
                    "description": "Append to this existing list. Pass either `list_id` or `title`."
                  },
                  "title": {
                    "type": "string",
                    "description": "Name for a new list, unique per shop. Pass this to create a list; posting to a title the shop already has appends to it. The response returns the `list_id`."
                  },
                  "handles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "1 to **10,000** TikTok handles per call, with or without a leading `@`. Normalized to lowercase; entries failing `[a-z0-9._]{1,30}` are dropped and reported in `invalid`."
                  },
                  "include_unmatched": {
                    "type": "boolean",
                    "description": "Default `false`: handles that don't resolve to a known creator are skipped (reported in `unmatched`). Set `true` to store them anyway — note automations can only message known creators."
                  }
                }
              },
              "example": {
                "list_id": 1421,
                "title": "Summer Creators",
                "handles": [
                  "@creatorone",
                  "creator.two",
                  "not_a_real_handle"
                ],
                "include_unmatched": false
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "list_id": {
                          "type": "number",
                          "description": "The list written to — pass this to the other list endpoints and to an automation's `list_ids`."
                        },
                        "title": {
                          "type": "string"
                        },
                        "submitted_count": {
                          "type": "integer",
                          "description": "Handles received in the request."
                        },
                        "resolved_count": {
                          "type": "integer",
                          "description": "Handles that matched a known creator."
                        },
                        "added_count": {
                          "type": "integer",
                          "description": "Rows actually written (excludes duplicates already in the list)."
                        },
                        "unmatched": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Valid handles that didn't match any known creator — skipped unless `include_unmatched`."
                        },
                        "invalid": {
                          "type": "array",
                          "items": {},
                          "description": "Entries dropped by normalization (illegal characters or over 30 chars)."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "List created.",
                        "list_id": 1421,
                        "title": "Summer Creators",
                        "submitted_count": 3,
                        "resolved_count": 2,
                        "added_count": 2,
                        "unmatched": [
                          "not_a_real_handle"
                        ],
                        "invalid": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "neither list_id nor title, empty handles, over the 10,000 cap,",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "neither list_id nor title, empty handles, over the 10,000 cap,",
                    "value": {
                      "error": "None of the handles matched a known creator. Pass include_unmatched=true to store them anyway.",
                      "unmatched": [
                        "..."
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/lists/list": {
      "post": {
        "operationId": "listsList",
        "summary": "Lists - List Lists",
        "description": "Browse and search every list on the shop, with live member counts. Pass `title` to resolve one exact name to its `list_id`. Each list reports how many of its members can be DM'd (`affiliate_count`) and how many can be emailed (`email_count`), so the same list can drive an automation and an email campaign.",
        "tags": [
          "Lists"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lists-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /lists/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "Optional. Page to fetch. Defaults to `1`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Results per page. Defaults to `25`, max `100`."
                  },
                  "title": {
                    "type": "string",
                    "description": "Optional. Exact list name, case-insensitive — this is how you resolve a name to the `list_id` that every other list endpoint and an automation's `list_ids` take. Titles are unique per shop, so a match returns exactly one list."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match against the list title, for browsing. Combine with `title` or use on its own."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "Optional. One of `created_at` (default), `title`, `affiliate_count`, or `email_count`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "Optional. `asc` or `desc` (default)."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "title": "Summer Creators",
                "search": "summer",
                "sort_by": "created_at",
                "sort_direction": "desc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "list_id": {
                                "type": "number",
                                "description": "The list's identifier — pass to `/lists/get`, `/lists/delete`, `/lists/rename`, `/lists/remove`, or an automation's `list_ids`."
                              },
                              "title": {
                                "type": "string",
                                "description": "The list's name, as shown in the dashboard. Editable via `POST /lists/rename`."
                              },
                              "affiliate_count": {
                                "type": "integer",
                                "description": "Distinct members carrying a TikTok handle: the audience a DM or invite campaign can reach."
                              },
                              "email_count": {
                                "type": "integer",
                                "description": "Distinct members carrying an email address: the audience an email campaign can reach."
                              },
                              "created_at": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "list_id": 1421,
                            "title": "Summer Creators",
                            "affiliate_count": 1975,
                            "email_count": 1204,
                            "created_at": "2026-07-01 21:16:30.559923"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 12,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/lists/get": {
      "post": {
        "operationId": "listsGet",
        "summary": "Lists - Get List Members",
        "description": "Fetch a list's members. Creator stats (nickname, followers, platform GMV, engagement) are joined live from the creator index at read time — they are never stale copies.",
        "tags": [
          "Lists"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lists-get"
        },
        "security": [
          {
            "apiKey": [
              "POST /lists/get"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "number",
                    "description": "The list's id. `404` when the list does not exist or belongs to another shop."
                  },
                  "identity": {
                    "type": "string",
                    "description": "Optional. Narrows to the members a channel can reach: `handle` for DM/invite outreach, `email` for email campaigns. Defaults to every member."
                  },
                  "page": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max page size `100`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max page size `100`."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "Optional. One of `affiliate` (handle), `email`, `followers`, `gmv`, `engagement`, or `created_at` (default)."
                  },
                  "sort_direction": {
                    "type": "string",
                    "description": "Optional. `asc` or `desc` (default)."
                  }
                }
              },
              "example": {
                "list_id": 1421,
                "identity": "handle",
                "page": 1,
                "page_size": 25,
                "sort_by": "gmv",
                "sort_direction": "desc"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "list_id": {
                          "type": "number",
                          "description": "The list's id — the identifier every other list endpoint takes."
                        },
                        "title": {
                          "type": "string"
                        },
                        "identity": {
                          "type": "string"
                        },
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "handle": {
                                "type": "string",
                                "description": "A member carries both where they are known, so one list can serve DM outreach and an email campaign."
                              },
                              "creator_oecuid": {
                                "type": "string"
                              },
                              "messaged": {
                                "type": "boolean",
                                "description": "Always `false`. Kept for payload stability."
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "nickname": {
                                "type": "string"
                              },
                              "email": {
                                "type": "string",
                                "description": "A member carries both where they are known, so one list can serve DM outreach and an email campaign."
                              },
                              "category": {
                                "type": "string"
                              },
                              "followers": {
                                "type": "number"
                              },
                              "affiliate_gmv": {
                                "type": "number",
                                "description": "The creator's platform-wide 30-day affiliate GMV."
                              },
                              "engagement": {
                                "type": "number",
                                "description": "Video engagement rate as percent × 100 (`512` = 5.12%)."
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "list_id": 1421,
                        "title": "Summer Creators",
                        "identity": "handle",
                        "results": [
                          {
                            "handle": "strangefruitugc",
                            "creator_oecuid": "7494855447334848677",
                            "messaged": false,
                            "created_at": "2026-07-01 21:16:30.559923",
                            "nickname": "Strange Fruit",
                            "email": "creator@example.com",
                            "category": "[\"Beauty & Personal Care\"]",
                            "followers": 48200,
                            "affiliate_gmv": 31250.5,
                            "engagement": 512
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 1975,
                        "has_more": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/lists/rename": {
      "post": {
        "operationId": "listsRename",
        "summary": "Lists - Rename List",
        "description": "Rename a list. Automations reference lists by `list_id`, so a rename does not affect any campaign targeting the list.",
        "tags": [
          "Lists"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lists-rename"
        },
        "security": [
          {
            "apiKey": [
              "POST /lists/rename"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "number",
                    "description": "The list to rename. `404` when the list does not exist or belongs to another shop."
                  },
                  "new_title": {
                    "type": "string",
                    "description": "Required. Max 255 chars, and must not collide with another of the shop's lists."
                  }
                },
                "required": [
                  "new_title"
                ]
              },
              "example": {
                "list_id": 1421,
                "new_title": "Summer Creators 2026"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "list_id": {
                          "type": "number"
                        },
                        "title": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "List renamed.",
                        "list_id": 1421,
                        "title": "Summer Creators 2026"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "unknown list_id, or a list belonging to another shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "unknown list_id, or a list belonging to another shop",
                    "value": {
                      "error": "List not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a list named new_title already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "a list named new_title already exists",
                    "value": {
                      "error": "A list with that title already exists"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/lists/merge": {
      "post": {
        "operationId": "listsMerge",
        "summary": "Lists - Merge Lists",
        "description": "Union two or more lists into a **new** list. The source lists are kept intact, and every member is copied with all of its identities — handle, email and creator id. Merging into a title that already exists is rejected with `409`. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Lists"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lists-merge"
        },
        "security": [
          {
            "apiKey": [
              "POST /lists/merge"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "Name for the new merged list — must not already exist."
                  },
                  "source_list_ids": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "description": "2+ `list_id` values to union. Must be unique, and must belong to your shop."
                  }
                }
              },
              "example": {
                "title": "All Summer Creators",
                "source_list_ids": [
                  1421,
                  1508
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "list_id": {
                          "type": "number"
                        },
                        "title": {
                          "type": "string"
                        },
                        "merged_count": {
                          "type": "integer",
                          "description": "Distinct creators written to the new list (duplicates across sources collapse to one)."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "Lists merged.",
                        "list_id": 1602,
                        "title": "All Summer Creators",
                        "merged_count": 2612
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "fewer than 2 sources, duplicate sources, or non-integer ids",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "fewer than 2 sources, duplicate sources, or non-integer ids",
                    "value": {
                      "error": "source_list_ids must contain at least 2 lists"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "none of the source lists exist (or all are empty)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "none of the source lists exist (or all are empty)",
                    "value": {
                      "error": "Source lists not found or empty"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "target title already exists; a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "target title already exists",
                    "value": {
                      "error": "A list with that title already exists"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/lists/remove": {
      "post": {
        "operationId": "listsRemove",
        "summary": "Lists - Remove Entries",
        "description": "Remove specific handles (or email addresses) from a list without deleting the list itself.",
        "tags": [
          "Lists"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lists-remove"
        },
        "security": [
          {
            "apiKey": [
              "POST /lists/remove"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "number",
                    "description": "The list to edit."
                  },
                  "identity": {
                    "type": "string",
                    "description": "Optional. Which column the entries match: `handle` (default, pass `handles`) or `email` (pass `emails`)."
                  },
                  "handles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Entries to remove. Handles are normalized the same way as on create, so `@CreatorOne` matches `creatorone`."
                  },
                  "emails": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Entries to remove. Handles are normalized the same way as on create, so `@CreatorOne` matches `creatorone`."
                  }
                }
              },
              "example": {
                "list_id": 1421,
                "identity": "handle",
                "handles": [
                  "@creatorone",
                  "creator.two"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "removed_count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Entries removed.",
                        "removed_count": 2
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/lists/delete": {
      "delete": {
        "operationId": "listsDelete",
        "summary": "Lists - Delete List",
        "description": "Hard-delete a list and every member in it. Refused with `400` while any non-archived campaign still targets the list — repoint or delete the automation first, so a sender never wakes up to a vanished audience. The body is parsed with `request.get_json(silent=True)` so a missing or unparseable body returns a clean `400` instead of `415`. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Lists"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#lists-delete"
        },
        "security": [
          {
            "apiKey": [
              "DELETE /lists/delete"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "list_id": {
                    "type": "number",
                    "description": "The list to delete. Obtain from `/lists/list` or `/lists/create`."
                  }
                }
              },
              "example": {
                "list_id": 1421
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "removed_count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "List deleted.",
                        "removed_count": 1975
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "the list is still referenced by a campaign",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "the list is still referenced by a campaign",
                    "value": {
                      "error": "Cannot delete list: it is in use by a campaign."
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "unknown list_id, or a list belonging to another shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "unknown list_id, or a list belonging to another shop",
                    "value": {
                      "error": "List not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/tags/list": {
      "post": {
        "operationId": "tagsList",
        "summary": "Tags - List Tags",
        "description": "List the shop's tags with how many creators carry each, or pass a `handle` to get one creator's tags.",
        "tags": [
          "Tags"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#tags-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /tags/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring to narrow tag names."
                  },
                  "handle": {
                    "type": "string",
                    "description": "Optional. A TikTok handle (with or without `@`); when given, the response is that creator's tags instead of the shop summary. `404` if the creator is not in the CRM."
                  }
                }
              },
              "example": {
                "search": "tier"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "tag": {
                                "type": "string"
                              },
                              "creator_count": {
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "handle": {
                          "type": "string"
                        },
                        "creator_oecuid": {
                          "type": "string"
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "handle": "creatorone",
                        "creator_oecuid": "7400000000000000001",
                        "tags": [
                          "Gold Tier 30%",
                          "VIP"
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/tags/add": {
      "post": {
        "operationId": "tagsAdd",
        "summary": "Tags - Tag Creators",
        "description": "Add one or more tags to one or more creators. Re-tagging a creator that already has the tag is a no-op, so the call is safe to repeat.",
        "tags": [
          "Tags"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#tags-add"
        },
        "security": [
          {
            "apiKey": [
              "POST /tags/add"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Tag names to add, 1–60 characters each. Case is kept as given."
                  },
                  "handles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "TikTok handles to tag, with or without `@`. Must be in the shop's CRM — unknown handles come back in `unmatched`."
                  }
                }
              },
              "example": {
                "tags": [
                  "VIP"
                ],
                "handles": [
                  "@creatorone",
                  "creator.two"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "tagged_count": {
                          "type": "integer",
                          "description": "creators matched in the CRM"
                        },
                        "added_count": {
                          "type": "integer",
                          "description": "new tag rows; the rest already had the tag"
                        },
                        "unmatched": {
                          "type": "array",
                          "items": {},
                          "description": "handles not in the CRM"
                        },
                        "invalid_handles": {
                          "type": "array",
                          "items": {}
                        },
                        "invalid_tags": {
                          "type": "array",
                          "items": {}
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Tags added.",
                        "tags": [
                          "VIP"
                        ],
                        "tagged_count": 2,
                        "added_count": 1,
                        "unmatched": [],
                        "invalid_handles": [],
                        "invalid_tags": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/tags/remove": {
      "post": {
        "operationId": "tagsRemove",
        "summary": "Tags - Remove Tags",
        "description": "Take tags off specific creators, or — when `handles` is omitted — delete the tags from every creator in the shop.",
        "tags": [
          "Tags"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#tags-remove"
        },
        "security": [
          {
            "apiKey": [
              "POST /tags/remove"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Tag names to remove (exact, case-sensitive)."
                  },
                  "handles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Optional. Creators to untag. Omit to delete the tag shop-wide; an empty array is rejected with `400` so a shop-wide delete is always explicit."
                  }
                }
              },
              "example": {
                "tags": [
                  "VIP"
                ],
                "handles": [
                  "@creatorone"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "removed_count": {
                          "type": "integer"
                        },
                        "unmatched": {
                          "type": "array",
                          "items": {}
                        },
                        "invalid_handles": {
                          "type": "array",
                          "items": {}
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Tags removed.",
                        "tags": [
                          "VIP"
                        ],
                        "removed_count": 1,
                        "unmatched": [],
                        "invalid_handles": []
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/workflows/list": {
      "post": {
        "operationId": "workflowsList",
        "summary": "Workflows - List Workflows",
        "description": "List the shop's workflows (deleted ones excluded), newest edited first.",
        "tags": [
          "Workflows"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#workflows-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /workflows/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "Optional. Defaults to `1`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Defaults to `25`, max `100`."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match against the workflow name."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "search": "onboarding"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "workflow_id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "description": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string",
                                "description": "active | paused"
                              },
                              "trigger_type": {
                                "type": "string",
                                "description": "creator_matches | recurring"
                              },
                              "step_count": {
                                "type": "integer"
                              },
                              "triggered": {
                                "type": "number",
                                "description": "creators that have entered, all time"
                              },
                              "template_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              },
                              "user_touched": {
                                "type": "boolean"
                              },
                              "updated_at": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "last_sync_at": {
                                "type": "string",
                                "format": "date-time"
                              }
                            }
                          }
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "workflow_id": "64b1a2c3d4e5f60718293a4b",
                            "name": "Welcome new creators",
                            "description": "onboarding flow for new creators",
                            "status": "active",
                            "trigger_type": "creator_matches",
                            "step_count": 4,
                            "triggered": 1284,
                            "template_id": null,
                            "user_touched": true,
                            "updated_at": "2026-08-26T12:24:27Z",
                            "last_sync_at": "2026-08-27T14:07:07Z"
                          }
                        ],
                        "total_count": 1,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/workflows/get": {
      "post": {
        "operationId": "workflowsGet",
        "summary": "Workflows - Get Workflow",
        "description": "One workflow with its trigger and full step graph. Each step carries its authored `config`, its `next` pointer, `branches` (`onTrue` / `onFalse`, used by conditions), and `triggered` — how many creators have reached it.",
        "tags": [
          "Workflows"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#workflows-get"
        },
        "security": [
          {
            "apiKey": [
              "POST /workflows/get"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "workflow_id": {
                    "type": "string",
                    "description": "From `/workflows/list`."
                  }
                }
              },
              "example": {
                "workflow_id": "64b1a2c3d4e5f60718293a4b"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "workflow_id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "trigger_type": {
                          "type": "string"
                        },
                        "step_count": {
                          "type": "integer"
                        },
                        "triggered": {
                          "type": "number"
                        },
                        "trigger": {
                          "type": "object",
                          "properties": {
                            "type": {
                              "type": "string"
                            },
                            "config": {
                              "type": "object",
                              "properties": {
                                "match": {
                                  "type": "string"
                                },
                                "conditions": {
                                  "type": "array",
                                  "items": {}
                                }
                              }
                            },
                            "next": {
                              "type": "string"
                            }
                          }
                        },
                        "steps": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string",
                                "description": "send_dm | send_tc_invite | send_tc_dm | send_tc_email | send_email | add_to_list | tag_creator | wait | wait_until | condition | exit"
                              },
                              "config": {
                                "type": "object",
                                "properties": {
                                  "messageItems": {
                                    "type": "array",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "type": {
                                          "type": "string"
                                        },
                                        "content": {
                                          "type": "string"
                                        }
                                      }
                                    }
                                  },
                                  "amount": {
                                    "type": "number"
                                  },
                                  "unit": {
                                    "type": "string"
                                  }
                                }
                              },
                              "next": {
                                "type": "string"
                              },
                              "branches": {
                                "type": "object",
                                "properties": {
                                  "onTrue": {},
                                  "onFalse": {}
                                }
                              },
                              "triggered": {
                                "type": "number"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "workflow_id": "64b1a2c3d4e5f60718293a4b",
                        "name": "Welcome new creators",
                        "status": "active",
                        "trigger_type": "creator_matches",
                        "step_count": 4,
                        "triggered": 1284,
                        "trigger": {
                          "type": "creator_matches",
                          "config": {
                            "match": "AND",
                            "conditions": []
                          },
                          "next": "s1"
                        },
                        "steps": [
                          {
                            "id": "s1",
                            "type": "send_dm",
                            "config": {
                              "messageItems": [
                                {
                                  "type": "message",
                                  "content": "Hi [affiliate_name]! ..."
                                }
                              ]
                            },
                            "next": "s2",
                            "branches": {
                              "onTrue": null,
                              "onFalse": null
                            },
                            "triggered": 1284
                          },
                          {
                            "id": "s2",
                            "type": "wait",
                            "config": {
                              "amount": 3,
                              "unit": "days"
                            },
                            "next": "s3",
                            "branches": {
                              "onTrue": null,
                              "onFalse": null
                            },
                            "triggered": 433
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/workflows/campaigns": {
      "post": {
        "operationId": "workflowsCampaigns",
        "summary": "Workflows - List Campaigns",
        "description": "The shop's community campaigns, as a workflow's Community conditions use them: each campaign's `id` (the `campaignId` a rule references), its type and status, what its type can drive, and the values a `campaign_progress` rule can pick (`tier:2`, `rank:1`, `cell`, `line`, `stage:accepted`). Ended campaigns are included — `campaign_winner` and the state operators still read them.",
        "tags": [
          "Workflows"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#workflows-campaigns"
        },
        "security": [
          {
            "apiKey": [
              "POST /workflows/campaigns"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "campaigns": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string",
                                "description": "contest | leaderboard | bingo | retainer | sweepstakes | race"
                              },
                              "status": {
                                "type": "string",
                                "description": "active | paused | completed"
                              },
                              "endDate": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "unit": {
                                "type": "string",
                                "description": "tier | rank | milestone | stage | null"
                              },
                              "values": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "id": {
                                      "type": "string"
                                    },
                                    "name": {
                                      "type": "string"
                                    },
                                    "meta": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "progressCapable": {
                                "type": "boolean"
                              },
                              "winnerCapable": {
                                "type": "boolean"
                              },
                              "summary": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "campaigns": [
                          {
                            "id": "6a0f1c2d3e4f5a6b7c8d9e0f",
                            "name": "Alpine Protein — Spring contest",
                            "type": "contest",
                            "status": "active",
                            "endDate": "2026-10-12T23:59:00.000Z",
                            "unit": "tier",
                            "values": [
                              {
                                "id": "tier:1",
                                "name": "Tier 1",
                                "meta": "$100 GMV · $20 cash"
                              },
                              {
                                "id": "tier:2",
                                "name": "Tier 2",
                                "meta": "$250 GMV · $40 cash"
                              }
                            ],
                            "progressCapable": true,
                            "winnerCapable": true,
                            "summary": "Contest · 2 tiers · ends Oct 12"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/workflows/create": {
      "post": {
        "operationId": "workflowsCreate",
        "summary": "Workflows - Create Workflow",
        "description": "Create a workflow from a trigger and a step graph — the same shape `/workflows/get` returns, so duplicating a workflow is a `get` followed by a `create` with a new name. The graph is validated exactly as the dashboard builder does (known step types, every `next` / branch pointer resolves to a step, no cycles, at most 200 steps); a shop can hold 100 live workflows. New workflows start paused with all counters at zero. Requires the Scale plan (`403` otherwise).\n\n**Condition rules (`config.conditions[]`):** `sample_request_status` (`is` | `is_not` — value `[status, …]`. Optional `scope`: `\"any\"` (default when absent) matches on any of the creator's requests; `\"latest\"` reads only the most recent request per product, so a re-requested product is judged by its newest request.), `sampled_products` (`is_any` | `is_all` | `is_only` | `is_not` — value `[product_id, …]`. Optional `skus: { product_id: [sku_id, …] }` narrows a listing to specific variations (flavour/size); a product without an entry matches any variation. `is_only` also rejects other variations of a narrowed listing.), `gmv` (`gte` | `lte` — number; `timeframeDays` optional.), `posts` (`gte` | `lte` — number. Optional `products: [product_id, …]` counts only posts featuring those products. Window: `timeframeDays` (rolling, last N days) or `since` (anchored) — `{ kind: \"date\", date: \"YYYY-MM-DD\" }`, `{ kind: \"entered\" }` (after the creator entered the workflow) or `{ kind: \"last_message\" }` (after your last message to them). `timeframeDays` and `since` are mutually exclusive; the run-relative kinds are rejected on the trigger.), `replied` (`is` — `true` / `false`.), `in_group` (`is_in` | `not_in` — group id.), `in_list` (`is_in` | `not_in` — a list id (number) or an array of up to 10 list ids; a creator in ANY of them matches.), `gender / age / race / body_type / economic_status / tone / language` (`is` — `[option, …]`, lowercase.)\n\nTrigger `config`, `condition` steps and `wait_until` steps share one shape: `{ match: \"AND\" | \"OR\", conditions: [{ id, field, operator, value, timeframeDays? }] }`. Unknown fields or operators are rejected at run time and the rule matches nobody, so use exactly these.",
        "tags": [
          "Workflows"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#workflows-create"
        },
        "security": [
          {
            "apiKey": [
              "POST /workflows/create"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Display name, up to 120 characters."
                  },
                  "description": {
                    "type": "string",
                    "description": "Optional, up to 500 characters."
                  },
                  "status": {
                    "type": "string",
                    "description": "Optional. `paused` (default) or `active`. An active workflow starts messaging creators on the next hourly tick — create paused and activate after reviewing it in the dashboard."
                  },
                  "trigger": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "properties": {
                      "type": {
                        "type": "string",
                        "description": "creator_matches | recurring"
                      },
                      "config": {
                        "type": [
                          "object",
                          "null"
                        ],
                        "properties": {
                          "match": {
                            "type": "string"
                          },
                          "conditions": {
                            "type": "array",
                            "items": {}
                          }
                        }
                      },
                      "next": {
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "description": "`{type, config, next}`. `next` is the id of the first step (or `null` for an empty workflow). For `creator_matches`, `config` is a condition group — see **Condition rules** below."
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "type": {
                          "type": "string"
                        },
                        "config": {
                          "type": "object",
                          "properties": {
                            "messageItems": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "type": {
                                    "type": "string"
                                  },
                                  "content": {
                                    "type": "string"
                                  }
                                }
                              }
                            },
                            "amount": {
                              "type": "number"
                            },
                            "unit": {
                              "type": "string"
                            }
                          }
                        },
                        "next": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "branches": {
                          "type": "object",
                          "properties": {
                            "onTrue": {},
                            "onFalse": {}
                          }
                        }
                      }
                    },
                    "description": "Array of `{id, type, config, next, branches}`. Ids only need to be unique within this workflow, so a graph copied from `/workflows/get` can be passed as-is; `triggered` counters on copied steps are ignored and reset to 0."
                  }
                }
              },
              "example": {
                "name": "Sample to First Sale (copy)",
                "description": "optional, up to 500 characters",
                "status": "paused",
                "trigger": {
                  "type": "creator_matches",
                  "config": {
                    "match": "AND",
                    "conditions": []
                  },
                  "next": "s1"
                },
                "steps": [
                  {
                    "id": "s1",
                    "type": "send_dm",
                    "config": {
                      "messageItems": [
                        {
                          "type": "message",
                          "content": "Hi [affiliate_name]!"
                        }
                      ]
                    },
                    "next": "s2",
                    "branches": {
                      "onTrue": null,
                      "onFalse": null
                    }
                  },
                  {
                    "id": "s2",
                    "type": "wait",
                    "config": {
                      "amount": 3,
                      "unit": "days"
                    },
                    "next": null,
                    "branches": {
                      "onTrue": null,
                      "onFalse": null
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "workflow_id": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "trigger_type": {
                          "type": "string"
                        },
                        "step_count": {
                          "type": "integer"
                        },
                        "triggered": {
                          "type": "number"
                        },
                        "template_id": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "user_touched": {
                          "type": "boolean"
                        },
                        "updated_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "last_sync_at": {}
                      }
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "error": "Step s2 points at a missing step"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/workflows/toggle": {
      "post": {
        "operationId": "workflowsToggle",
        "summary": "Workflows - Activate / Pause",
        "description": "Set a workflow to `active` or `paused`. Pausing stops new sends; creators already inside keep their place and resume when it is reactivated. Requires the Scale plan (`403` otherwise).",
        "tags": [
          "Workflows"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#workflows-toggle"
        },
        "security": [
          {
            "apiKey": [
              "POST /workflows/toggle"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "workflow_id": {
                    "type": "string",
                    "description": "From `/workflows/list`."
                  },
                  "status": {
                    "type": "string",
                    "description": "`active` or `paused`."
                  }
                }
              },
              "example": {
                "workflow_id": "64b1a2c3d4e5f60718293a4b",
                "status": "paused"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Workflow set to paused"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/workflows/delete": {
      "delete": {
        "operationId": "workflowsDelete",
        "summary": "Workflows - Delete Workflow",
        "description": "Delete a workflow. It is paused and hidden immediately; queued sends are dropped and creators inside it are released during the next executor pass. Same behaviour as deleting from the dashboard.",
        "tags": [
          "Workflows"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#workflows-delete"
        },
        "security": [
          {
            "apiKey": [
              "DELETE /workflows/delete"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "workflow_id": {
                    "type": "string",
                    "description": "From `/workflows/list`. `404` if already deleted."
                  }
                }
              },
              "example": {
                "workflow_id": "64b1a2c3d4e5f60718293a4b"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Workflow deleted."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/creator-briefs/create": {
      "post": {
        "operationId": "briefsCreate",
        "summary": "Creator Briefs - Create Brief",
        "description": "Create a creator brief and get back its shareable link. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.\n\n**`dynamic_content.sort_by` / `default_time_range` / `linked_handles_mode`:** `sort_by: gmv` (Feature the highest-GMV videos (default).), `sort_by: views` (Feature the most-viewed videos.), `default_time_range: 1d | 7d | 30d | all` (Initial time window creators see (default `30d`).), `linked_handles_mode: hide` (Exclude videos from creators already linked to your shop.), `linked_handles_mode: only` (Only videos from your linked creators.), `linked_handles_mode: null` (No restriction (default).)\n\n**Guideline types (`guidelines[].type`):** `do` (A practice to follow — rendered with a check.), `dont` (A practice to avoid — rendered with a cross.)\n\n**Page sections (`section_order`):** `videos`, `hooks`, `guidelines`, `community`, `pdf`, `textbox`",
        "tags": [
          "Creator Briefs"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#briefs-create"
        },
        "security": [
          {
            "apiKey": [
              "POST /creator-briefs/create"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Limits:** max **500** briefs per shop (`403` past the cap); requires the **Scale plan** (`403` otherwise). The info-PDF upload is dashboard-only; `pdf_button_text` / `pdf_button_color` may still be set via the API.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Both required. `name` is the internal label; `headline` is the page title creators see."
                  },
                  "headline": {
                    "type": "string",
                    "description": "Both required. `name` is the internal label; `headline` is the page title creators see."
                  },
                  "brief_type": {
                    "type": "string",
                    "description": "`static` (fixed page, default) or `dynamic` (per-product live content — creators pick a product and see its top videos/hooks, always current)."
                  },
                  "video_mode": {
                    "type": "string",
                    "description": "Static briefs only: `manual` (you provide `video_urls`) or `auto` (the page features the shop's top videos per `dynamic_content`). Dynamic briefs are always auto."
                  },
                  "video_urls": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "TikTok video URLs to feature. Required (≥1) for static + manual; ignored for auto/dynamic."
                  },
                  "dynamic_content": {
                    "type": "object",
                    "properties": {
                      "all_products": {
                        "type": "boolean"
                      },
                      "products": {
                        "type": "array",
                        "items": {}
                      },
                      "video_count": {
                        "type": "integer"
                      },
                      "sort_by": {
                        "type": "string"
                      },
                      "default_time_range": {
                        "type": "string"
                      },
                      "linked_handles_mode": {}
                    },
                    "description": "Video-sourcing rules for auto/dynamic briefs: `all_products` (default `true`) or a `products` id array (**required for dynamic when `all_products` is false**); `video_count` 1-50 (default 5); `sort_by`; `past_months` (default 12) / `all_time`; `default_time_range`; `linked_handles_mode` — expand the references below."
                  },
                  "top_hooks": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Opening-hook suggestions shown to creators."
                  },
                  "guidelines": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string"
                        }
                      }
                    },
                    "description": "Array of `{ type, description }` do/don't rules — expand **Guideline types** below."
                  },
                  "support_email": {
                    "type": "string",
                    "description": "Contact email shown on the brief (validated)."
                  },
                  "text_box_title": {
                    "type": "string",
                    "description": "Optional free-text section on the page."
                  },
                  "text_box_body": {
                    "type": "string",
                    "description": "Optional free-text section on the page."
                  },
                  "show_hub_link": {
                    "type": "boolean",
                    "description": "Toggle the community-hub button and active-campaign cards."
                  },
                  "show_campaigns": {
                    "type": "boolean",
                    "description": "Toggle the community-hub button and active-campaign cards."
                  },
                  "section_order": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Order of the page sections — expand **Page sections** below."
                  }
                }
              },
              "example": {
                "name": "Glow Serum launch brief",
                "headline": "Post like our top sellers",
                "brief_type": "static",
                "video_mode": "manual",
                "video_urls": [
                  "https://www.tiktok.com/@creator/video/7350000000000000000"
                ],
                "dynamic_content": {
                  "all_products": true,
                  "products": [],
                  "video_count": 5,
                  "sort_by": "gmv",
                  "default_time_range": "30d",
                  "linked_handles_mode": null
                },
                "top_hooks": [
                  "Wait until you see the results..."
                ],
                "guidelines": [
                  {
                    "type": "do",
                    "description": "Show the product clearly within the first 3 seconds"
                  },
                  {
                    "type": "dont",
                    "description": "Avoid false claims"
                  }
                ],
                "support_email": "creators@example.com",
                "text_box_title": "Payment terms",
                "text_box_body": "Commission is paid out weekly...",
                "show_hub_link": false,
                "show_campaigns": false,
                "section_order": [
                  "videos",
                  "hooks",
                  "guidelines",
                  "community",
                  "pdf",
                  "textbox"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "brief_id": {
                          "type": "string"
                        },
                        "url_code": {
                          "type": "string",
                          "description": "The 6-character identifier inside the link. Stable for the brief's lifetime."
                        },
                        "link": {
                          "type": "string",
                          "description": "The brief's public URL — paste this into an automation's invite message or DM content to send it to creators."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "Creator brief created.",
                        "brief_id": "6a1f00c89b3e21504d7ab911",
                        "url_code": "ab12cd",
                        "link": "https://cruva.com/fw?id=ab12cd"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation error (the specific field is named)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "plan ineligible, or 50-brief cap reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "plan ineligible, or 50-brief cap reached",
                    "value": {
                      "error": "Creator briefs require the Scale plan."
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/creator-briefs/update": {
      "post": {
        "operationId": "briefsUpdate",
        "summary": "Creator Briefs - Update Brief",
        "description": "**Partial update** — only the fields present in the request change. Accepts the same fields as [Create Brief](https://cruva.com/docs/api#briefs-create) plus `brief_id`. The brief's **link never changes**, so automations already sending it keep working: the page simply updates in place. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Creator Briefs"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#briefs-update"
        },
        "security": [
          {
            "apiKey": [
              "POST /creator-briefs/update"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "brief_id": {
                    "type": "string",
                    "description": "The brief to edit. Obtain from `/creator-briefs/list`."
                  },
                  "headline": {
                    "type": "string"
                  },
                  "top_hooks": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "example": {
                "brief_id": "6a1f00c89b3e21504d7ab911",
                "headline": "Updated: post like our best sellers",
                "top_hooks": [
                  "New hook that converts"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "brief_id": {
                          "type": "string"
                        },
                        "url_code": {
                          "type": "string"
                        },
                        "link": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Creator brief updated.",
                        "brief_id": "6a1f00c89b3e21504d7ab911",
                        "url_code": "ab12cd",
                        "link": "https://cruva.com/fw?id=ab12cd"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation error on the merged result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "validation error on the merged result",
                    "value": {
                      "error": "dynamic briefs need products: set dynamic_content.all_products to true or provide dynamic_content.products"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "not found, or not owned by this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "not found, or not owned by this shop",
                    "value": {
                      "error": "Creator brief not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/creator-briefs/list": {
      "post": {
        "operationId": "briefsList",
        "summary": "Creator Briefs - List Briefs",
        "description": "List the shop's creator briefs — including each brief's shareable `link` and view count. Pass `brief_id` to fetch a single brief's full configuration.",
        "tags": [
          "Creator Briefs"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#briefs-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /creator-briefs/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max page size `100`. Sorted by most recently updated."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max page size `100`. Sorted by most recently updated."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match on the brief name."
                  },
                  "brief_id": {
                    "type": "string",
                    "description": "Optional. Fetch a single brief."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "search": "serum",
                "brief_id": ""
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "brief_id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "headline": {
                                "type": "string"
                              },
                              "brief_type": {
                                "type": "string"
                              },
                              "video_mode": {
                                "type": "string"
                              },
                              "link": {
                                "type": "string",
                                "description": "The brief's public URL — drop it into an automation's invite message or DM content."
                              },
                              "url_code": {
                                "type": "string"
                              },
                              "views": {
                                "type": "number",
                                "description": "How many times the brief page has been opened."
                              },
                              "video_urls": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "video_count": {
                                "type": "integer",
                                "description": "Featured video count — the manual list's length, or `dynamic_content.video_count` for auto/dynamic briefs."
                              },
                              "top_hooks": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "guidelines": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "type": {
                                      "type": "string"
                                    },
                                    "description": {
                                      "type": "string"
                                    }
                                  }
                                }
                              },
                              "support_email": {
                                "type": "string"
                              },
                              "has_pdf": {
                                "type": "boolean"
                              },
                              "dynamic_content": {},
                              "show_hub_link": {
                                "type": "boolean"
                              },
                              "show_campaigns": {
                                "type": "boolean"
                              },
                              "section_order": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "last_updated_at": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "brief_id": "6a1f00c89b3e21504d7ab911",
                            "name": "Glow Serum launch brief",
                            "headline": "Post like our top sellers",
                            "brief_type": "static",
                            "video_mode": "manual",
                            "link": "https://cruva.com/fw?id=ab12cd",
                            "url_code": "ab12cd",
                            "views": 412,
                            "video_urls": [
                              "https://www.tiktok.com/@creator/video/7350000000000000000"
                            ],
                            "video_count": 1,
                            "top_hooks": [
                              "Wait until you see the results..."
                            ],
                            "guidelines": [
                              {
                                "type": "do",
                                "description": "Show the product clearly within the first 3 seconds"
                              }
                            ],
                            "support_email": "creators@example.com",
                            "has_pdf": false,
                            "dynamic_content": null,
                            "show_hub_link": false,
                            "show_campaigns": false,
                            "section_order": [
                              "videos",
                              "hooks",
                              "guidelines",
                              "community",
                              "pdf",
                              "textbox"
                            ],
                            "created_at": "2026-07-01 18:20:11.000000",
                            "last_updated_at": "2026-07-18 09:03:42.000000"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 6,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/creator-briefs/delete": {
      "delete": {
        "operationId": "briefsDelete",
        "summary": "Creator Briefs - Delete Brief",
        "description": "Delete a brief. It disappears from [List Creator Briefs](https://cruva.com/docs/api#briefs-list) and the dashboard, and its public link stops resolving **immediately** — any automation message that already sent the link will point at a dead page, so update the automation copy first. The body is parsed with `request.get_json(silent=True)` so a missing or unparseable body returns a clean `400` instead of `415`. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Creator Briefs"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#briefs-delete"
        },
        "security": [
          {
            "apiKey": [
              "DELETE /creator-briefs/delete"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "brief_id": {
                    "type": "string",
                    "description": "The brief to delete. Obtain from `/creator-briefs/list`."
                  }
                }
              },
              "example": {
                "brief_id": "6a1f00c89b3e21504d7ab911"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Creator brief deleted."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "missing or malformed brief_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "missing or malformed brief_id",
                    "value": {
                      "error": "Missing brief_id"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "not found, or not owned by this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "not found, or not owned by this shop",
                    "value": {
                      "error": "Creator brief not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/list": {
      "post": {
        "operationId": "communityCampaignsList",
        "summary": "Community - List Campaigns",
        "description": "List the community campaigns configured for the shop, with their public share links. Paginated; filterable by title, lifecycle status, and campaign type.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaigns-list"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "Optional. Page to fetch. Defaults to `1`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Number of results per page. Defaults to `25`, max `100`."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match against the campaign title."
                  },
                  "status": {
                    "type": "string",
                    "description": "Optional. One of `active`, `paused`, or `completed`."
                  },
                  "campaign_type": {
                    "type": "string",
                    "description": "Optional. One of `race`, `contest`, `leaderboard`, `bingo`, `sweepstakes`, or `retainer`."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "search": "",
                "status": "active",
                "campaign_type": "race"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "campaign_id": {
                                "type": "string",
                                "description": "Identifier to pass to every other `/community/campaigns/*` endpoint."
                              },
                              "title": {
                                "type": "string"
                              },
                              "campaign_type": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "url": {
                                "type": "string"
                              },
                              "share_link": {
                                "type": "string",
                                "description": "The public join URL (`https://creators.cruva.com/<url>`). Put this in outreach automation messages to invite creators."
                              },
                              "start_date": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "end_date": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "timezone": {
                                "type": "string"
                              },
                              "payout_type": {
                                "type": "string",
                                "description": "`cash`, `prize`, or `both` — under `both` each tier pays cash, awards a prize, or does both (mixed freely across tiers)."
                              },
                              "content_types": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "`content_types` is the multi-select source of truth (any combination of `video`, `LIVE`, `photo` — photo = TikTok photo-mode slideshow). `content_type` is the legacy single-value mirror; any combination collapses to `both` (historically video + LIVE)."
                              },
                              "content_type": {
                                "type": "string",
                                "description": "`content_types` is the multi-select source of truth (any combination of `video`, `LIVE`, `photo` — photo = TikTok photo-mode slideshow). `content_type` is the legacy single-value mirror; any combination collapses to `both` (historically video + LIVE)."
                              },
                              "progress_metric": {
                                "type": "string"
                              },
                              "require_approval": {
                                "type": "boolean",
                                "description": "`true` means the campaign is invite-only — creators apply and wait in `pending` until approved via `/community/campaigns/participants/set_status`."
                              },
                              "budget": {
                                "type": "number"
                              },
                              "is_recurring": {
                                "type": "boolean"
                              },
                              "creators_applied": {
                                "type": "number"
                              },
                              "creators_joined": {
                                "type": "number"
                              },
                              "total_gmv": {
                                "type": "number",
                                "description": "Lifetime campaign totals (GMV generated, payouts recorded, videos posted)."
                              },
                              "total_spent": {
                                "type": "number",
                                "description": "Lifetime campaign totals (GMV generated, payouts recorded, videos posted)."
                              },
                              "videos": {
                                "type": "number",
                                "description": "Lifetime campaign totals (GMV generated, payouts recorded, videos posted)."
                              },
                              "created_at": {
                                "type": "string"
                              },
                              "last_updated_at": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "campaign_id": "6a61ef6bcc6388012e941c8f",
                            "title": "Summer Views Race",
                            "campaign_type": "race",
                            "status": "active",
                            "url": "wpasve",
                            "share_link": "https://creators.cruva.com/wpasve",
                            "start_date": "2026-07-01T00:00:00+00:00",
                            "end_date": "2026-08-01T00:00:00+00:00",
                            "timezone": "America/New_York",
                            "payout_type": "cash",
                            "content_types": [
                              "video"
                            ],
                            "content_type": "video",
                            "progress_metric": "views",
                            "require_approval": false,
                            "budget": 5000,
                            "is_recurring": false,
                            "creators_applied": 42,
                            "creators_joined": 37,
                            "total_gmv": 13397.42,
                            "total_spent": 1200,
                            "videos": 6154,
                            "created_at": "2026-06-02T14:11:08.213000",
                            "last_updated_at": "2026-07-20T02:15:44.001000"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 11,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/get": {
      "post": {
        "operationId": "communityCampaignsGet",
        "summary": "Community - Get Campaign",
        "description": "Fetch a single campaign's full configuration — everything stored on the campaign document (config, tiers, branding, products, guidelines, bingo/sweepstakes config) plus the assembled `share_link`.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaigns-get"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/get"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign to fetch. Obtain from `/community/campaigns/list`."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "campaign": {
                          "type": "object",
                          "properties": {
                            "campaign_id": {
                              "type": "string"
                            },
                            "campaign_type": {
                              "type": "string"
                            },
                            "status": {
                              "type": "string"
                            },
                            "url": {
                              "type": "string"
                            },
                            "share_link": {
                              "type": "string"
                            },
                            "config": {
                              "type": "object",
                              "properties": {
                                "title": {
                                  "type": "string"
                                },
                                "description": {
                                  "type": "string"
                                },
                                "start_date": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "end_date": {
                                  "type": "string",
                                  "format": "date-time"
                                },
                                "payout_type": {
                                  "type": "string"
                                },
                                "payout_method": {
                                  "type": "string"
                                },
                                "require_approval": {
                                  "type": "boolean"
                                },
                                "content_types": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "content_type": {
                                  "type": "string"
                                },
                                "progress_metric": {
                                  "type": "string"
                                },
                                "grace_period": {
                                  "type": "number"
                                },
                                "budget": {
                                  "type": "number"
                                },
                                "discord": {
                                  "type": "object",
                                  "properties": {
                                    "assign_roles": {
                                      "type": "boolean"
                                    },
                                    "roles": {
                                      "type": "array",
                                      "items": {}
                                    },
                                    "channel_enabled": {
                                      "type": "boolean"
                                    },
                                    "dm_enabled": {
                                      "type": "boolean"
                                    }
                                  }
                                },
                                "chat": {
                                  "type": "object",
                                  "properties": {
                                    "channel_enabled": {
                                      "type": "boolean"
                                    },
                                    "channel_posting_policy": {
                                      "type": "string"
                                    },
                                    "participant_status": {
                                      "type": "string"
                                    },
                                    "payouts": {
                                      "type": "string"
                                    },
                                    "winners": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "...": {
                                  "type": "string"
                                }
                              }
                            },
                            "tiers": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "level": {
                                    "type": "number"
                                  },
                                  "payout": {
                                    "type": "number"
                                  },
                                  "rate_per_view": {
                                    "type": "number"
                                  }
                                }
                              }
                            },
                            "products": {
                              "type": "object",
                              "properties": {
                                "enable_all_shop_products": {
                                  "type": "boolean"
                                },
                                "product_list": {
                                  "type": "array",
                                  "items": {}
                                }
                              }
                            },
                            "reminders": {
                              "type": "object",
                              "properties": {
                                "enabled": {
                                  "type": "boolean"
                                },
                                "reminders": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "days_before": {
                                        "type": "number"
                                      },
                                      "message": {
                                        "type": "string"
                                      }
                                    }
                                  }
                                }
                              }
                            },
                            "guidelines": {
                              "type": "array",
                              "items": {}
                            },
                            "creators_joined": {
                              "type": "number"
                            },
                            "total_gmv": {
                              "type": "number"
                            },
                            "total_spent": {
                              "type": "number"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "campaign": {
                          "campaign_id": "6a61ef6bcc6388012e941c8f",
                          "campaign_type": "race",
                          "status": "active",
                          "url": "wpasve",
                          "share_link": "https://creators.cruva.com/wpasve",
                          "config": {
                            "title": "Summer Views Race",
                            "description": "Post videos, earn from the pool.",
                            "start_date": "2026-07-01T00:00:00+00:00",
                            "end_date": "2026-08-01T00:00:00+00:00",
                            "payout_type": "cash",
                            "payout_method": "stripe",
                            "require_approval": false,
                            "content_types": [
                              "video"
                            ],
                            "content_type": "video",
                            "progress_metric": "views",
                            "grace_period": 3,
                            "budget": 0,
                            "discord": {
                              "assign_roles": false,
                              "roles": [],
                              "channel_enabled": false,
                              "dm_enabled": false
                            },
                            "chat": {
                              "channel_enabled": true,
                              "channel_posting_policy": "brand_only",
                              "participant_status": "dm",
                              "payouts": "dm",
                              "winners": "dm"
                            },
                            "...": "..."
                          },
                          "tiers": [
                            {
                              "level": 1,
                              "payout": 5000,
                              "rate_per_view": 0.003
                            }
                          ],
                          "products": {
                            "enable_all_shop_products": true,
                            "product_list": []
                          },
                          "reminders": {
                            "enabled": true,
                            "reminders": [
                              {
                                "days_before": 3,
                                "message": "..."
                              }
                            ]
                          },
                          "guidelines": [],
                          "creators_joined": 37,
                          "total_gmv": 13397.42,
                          "total_spent": 1200
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/create": {
      "post": {
        "operationId": "communityCampaignsCreate",
        "summary": "Community - Create Campaign",
        "description": "Create a community campaign and get back its public **share link**. The campaign appears in the dashboard and goes live at the link immediately when `status` is `active` (the default). Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.\n\nTo invite creators, put the returned `share_link` in an outreach automation message on [/automations/create](https://cruva.com/docs/api#automations-create).\n\n**`campaign_type` — contest formats:** `race` (Creators earn from a shared prize pool per video posted (or per view) — first come, first served until the pool runs out.), `contest` (Hit a threshold (GMV / videos / views) to win a tier prize; optional winner cap per tier.), `leaderboard` (Top-ranked creators at campaign end win, ordered by the progress metric.), `bingo` (Grid of challenges; completing a row/column/diagonal wins.), `sweepstakes` (Points-based raffle — GMV/views/posts earn entries; one winner drawn.), `retainer` (Fixed payment for N videos per period; supports fixed, weekly/monthly recurring, and dynamic (per-creator) schedules.)\n\n**`tiers` shape by campaign_type:** `race (posting)` (`[{ \"level\": 1, \"payout\": <total pool $>, \"amount_per_video\": <$ per video> }]` — one tier; creators drain the pool per posted video. Always cash.), `race (views)` (`[{ \"level\": 1, \"payout\": <total pool $>, \"rate_per_view\": 0.003 }]` — $ per single view (0.003 = $3 per 1K views). Always cash.), `contest` (`[{ \"level_gmv\": 500, \"payout\": 100, \"limit\": 10 }]` — at least one of `level_gmv`/`level_quantity`/`level_views` per tier sets the bar; `limit` caps winners per tier (whole number ≥ 1; first-come, overflow cascades to the next lower tier; omit for unlimited). Under `both`, a tier may award `prizes` instead of (or as well as) `payout`.), `leaderboard` (`[{ \"level\": 1, \"payout\": 500 }, { \"level\": 2, \"payout\": 250 }]` — `level` is the RANK; must be unique and ascending. Under `both`, ranks may mix cash and prize rewards.), `retainer` (`[{ \"level\": 4, \"payout\": 200 }]` — `level` is the number of videos required per period (`level_quantity` accepted as an alias). Always cash.), `bingo / sweepstakes` (One tier carrying the reward: `[{ \"payout\": 500 }]` (cash), `[{ \"prizes\": [{ \"title\": \"AirPods Pro\" }] }]` (prize), or both on the same tier.)\n\nCash tiers set `payout`; prize tiers set `prizes: [{ \"title\": \"...\" }]`; under `payout_type: \"both\"` each tier may carry either or both. Only contests use the `level_gmv`/`level_quantity`/`level_views` threshold fields — every other type uses `level`.\n\n**allowed content kinds & metrics:** `retainer` (any combination of kinds; metric is always `posting` (defaulted).), `contest / leaderboard` (any combination of kinds; any metric.), `sweepstakes` (any combination of kinds; no metric — scored by `point_rules` over the counted posts.), `race` (single kind only: `video`+`posting`, `LIVE`+`posting`, or `video`+`views` (no photo).), `bingo` (`video` only; progress comes from the grid cells.)\n\n`content_types` accepts any combination of `video`, `LIVE`, `photo` where noted. The legacy `content_type` mirror collapses combinations to `both` (which has always meant video + LIVE — it never includes photo).\n\n**retainer schedule modes (`start_date_type`):** `fixed` (One shared calendar window: `start_date` → `end_date` (both required).), `recurring` (Rolling weekly/monthly periods. Set `is_recurring: true` + `recurrence_period` (+ optional `max_periods`). `end_date` is computed server-side as the end of the FIRST period (weekly: +7 days; monthly: +1 month, month-end clamped). Grace period forced off. Contests may also use this mode.), `dynamic` (No shared window — each creator's period starts when THEY join and runs `duration_days` (default 30). `start_date`/`end_date` are auto-stamped placeholders (today / +10 years); omit them. Pairs with `creator_custom_settings`, `negotiation_enabled`, and `is_private`. Retainer only.)\n\n**`bingo.cells[].field_type` — bingo challenge types:** `total_gmv_above`, `highest_gmv_one_video`, `videos_count_above_gmv`, `total_views_above`, `highest_views_one_video`, `videos_count_above_views`, `total_likes_above`, `highest_likes_one_video`, `videos_count_above_likes`, `post_days_in_row`, `post_videos_one_day`\n\nEvery cell needs `value_x` (threshold or count). The `videos_count_above_*` types additionally need `value_y` (the per-video threshold).\n\n**reminder message variables:** `[name]` (Creator's name — all campaign types.), `[videosLeft]` (Videos still needed — retainer and race.), `[ranking]` (Creator's current rank — leaderboard.), `[topPrize]` (Top prize — leaderboard.), `[progressRemainingToNextTier]` (Progress remaining to the next tier — contest.), `[prizesRemaining]` (Prizes remaining — race.), `[prizePoolLeft]` (Prize pool remaining — race.), `[cellsCompleted]` (Bingo cells completed — bingo.), `[prize]` (The prize — bingo and sweepstakes.)\n\nSubstituted per creator when the reminder is sent. `[name]` works on every campaign type; the rest are type-specific.\n\n**`config_extras` keys:** `max_payout_per_creator` (Race only — cap on how much one creator can earn from the pool.), `max_views_per_video` (Views races only — cap on views counted per video.), `min_gmv_threshold` (Leaderboard, sweepstakes, and retainer — minimum threshold to qualify (leaderboard: progress metric's unit; sweepstakes/retainer: GMV).), `min_posts_threshold` (Leaderboard, sweepstakes, and retainer — optional minimum counted posts to qualify, in addition to min_gmv_threshold.), `winner_message` (Custom message sent to winners on completion (blank = default).), `disable_winner_emails / disable_winner_texts` (Suppress winner notifications.), `hide_terms` (Hide the terms & services section on the campaign page.), `count_videos_from_join_date` (Only count videos posted after each creator joined.), `short_header` (Short header shown on the campaign card.), `join_button_text` (Custom label for the join button.), `approval_message / rejection_message` (Copy sent on approve/reject (invite-only campaigns).), `require_stripe_setup / require_phone_number` (Extra join requirements.), `campaign_image` (Campaign image (S3 key).)\n\nsnake_case; converted to the stored config server-side. Anything settable on `config` can go here — these are the useful ones.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaigns-create"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/create"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Limits:** community campaigns require the **Scale plan** (403 otherwise), and a shop may have at most **100** campaigns (403 at the cap). A duplicate title within the shop returns `409`.\n**Casing:** the API accepts and returns snake_case everywhere; conversion to the stored document happens server-side.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "description": "required, unique per shop"
                  },
                  "description": {
                    "type": "string",
                    "description": "required, shown to creators"
                  },
                  "campaign_type": {
                    "type": "string",
                    "description": "What kind of contest this is — expand **contest formats** below. Determines the required `tiers` shape (expand **tiers shape by campaign_type**)."
                  },
                  "payout_type": {
                    "type": "string",
                    "description": "`\"cash\"` (Stripe payouts), `\"prize\"` (physical prizes), or `\"both\"` — under `both`, each tier pays cash, awards a prize, or does both, mixed freely across tiers. Optional: when omitted, contest/leaderboard/sweepstakes/bingo derive it from what the tiers carry (cash only → `cash`, prizes only → `prize`, any mix → `both`); races and retainers default to `cash`."
                  },
                  "start_date": {
                    "type": "string",
                    "format": "date",
                    "description": "ISO date; omit for dynamic retainers"
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date",
                    "description": "required for fixed schedules"
                  },
                  "tiers": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "level": {
                          "type": "number"
                        },
                        "payout": {
                          "type": "number"
                        },
                        "rate_per_view": {
                          "type": "number"
                        }
                      }
                    },
                    "description": "Prize/payout ladder. The shape depends on `campaign_type` — expand the table below. Cash tiers set `payout`; prize tiers set `prizes: [{ \"title\": \"AirPods Pro\", \"image_path\": \"...\" }]`; under `payout_type: \"both\"` a tier may carry either or both (a tier with neither is rejected). A tier can also set `\"reward_type\": \"cash\" | \"prize\" | \"both\"` to gate its own fields (`cash` drops the prize rows, `prize` clears the cash amount); input-only, never stored. Blank prize rows are dropped."
                  },
                  "content_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "`content_types` is the kinds of shoppable post the campaign counts — any combination of `video`, `LIVE`, `photo` (TikTok photo-mode slideshow); default `[\"video\"]`. The legacy single-value `content_type` is still accepted (`both` = video + LIVE). Not every combo is valid per type — expand **allowed content kinds & metrics** below. `progress_metric` is ignored for sweepstakes (scored by `point_rules`) and defaults to `posting` for retainers."
                  },
                  "progress_metric": {
                    "type": "string",
                    "description": "`content_types` is the kinds of shoppable post the campaign counts — any combination of `video`, `LIVE`, `photo` (TikTok photo-mode slideshow); default `[\"video\"]`. The legacy single-value `content_type` is still accepted (`both` = video + LIVE). Not every combo is valid per type — expand **allowed content kinds & metrics** below. `progress_metric` is ignored for sweepstakes (scored by `point_rules`) and defaults to `posting` for retainers."
                  },
                  "timezone": {
                    "type": "string"
                  },
                  "require_approval": {
                    "type": "boolean",
                    "description": "When `true` the campaign is invite-only: creators apply into a `pending` queue and must be approved via [/community/campaigns/participants/set_status](https://cruva.com/docs/api#community-participants-set-status) before they count."
                  },
                  "budget": {
                    "type": "number",
                    "description": "`budget` is only enforced on **cash-bearing contests** (`cash`/`both`; stored as `0` for every other type — a race's pool lives in `tiers[0].payout`). `hide_budget_card` hides the spend figure from creators (the contest budget well / race prize-pool bar) — display only, the budget still caps funding; meaningful on races and budget-enforced cash contests. `grace_period` (default `3`) is how many days after the end date posted content still counts; **forced to 0 on recurring campaigns** (periods are contiguous calendar windows)."
                  },
                  "hide_budget_card": {
                    "type": "boolean",
                    "description": "`budget` is only enforced on **cash-bearing contests** (`cash`/`both`; stored as `0` for every other type — a race's pool lives in `tiers[0].payout`). `hide_budget_card` hides the spend figure from creators (the contest budget well / race prize-pool bar) — display only, the budget still caps funding; meaningful on races and budget-enforced cash contests. `grace_period` (default `3`) is how many days after the end date posted content still counts; **forced to 0 on recurring campaigns** (periods are contiguous calendar windows)."
                  },
                  "auto_assign_tiers": {
                    "type": "boolean",
                    "description": "Contests only (default `true`). When `false`, tiers are never assigned automatically — the brand sets each creator's tier manually from the dashboard's participants table."
                  },
                  "grace_period": {
                    "type": "number",
                    "description": "`budget` is only enforced on **cash-bearing contests** (`cash`/`both`; stored as `0` for every other type — a race's pool lives in `tiers[0].payout`). `hide_budget_card` hides the spend figure from creators (the contest budget well / race prize-pool bar) — display only, the budget still caps funding; meaningful on races and budget-enforced cash contests. `grace_period` (default `3`) is how many days after the end date posted content still counts; **forced to 0 on recurring campaigns** (periods are contiguous calendar windows)."
                  },
                  "usage_rights": {
                    "type": "string"
                  },
                  "product_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "default = all shop products"
                  },
                  "guidelines": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "inspiration_links": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Example TikTok video URLs shown in the join page's inspiration section. (The dashboard can also auto-fill this section from the shop's top content — `inspiration_video_mode: \"auto\"` + `inspiration_auto_video_config`.)"
                  },
                  "reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "\"N days before the end\" nudges over four channels. `reminders` goes out via SMS/email; `discord_reminders` posts to a channel and needs `channel_id`/`channel_name` from the shop's Discord integration; `lark_reminders` posts to the shop's connected Lark group; `chat_reminders` lands as campaign-chat system messages with `destination: \"channel\" | \"dm\"`. Each item needs `days_before` (integer ≥ 1) and `message` (blank-message rows are dropped). Messages support variables — expand **reminder message variables** below."
                  },
                  "discord_reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "channel_id": {
                        "type": "string"
                      },
                      "channel_name": {
                        "type": "string"
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "\"N days before the end\" nudges over four channels. `reminders` goes out via SMS/email; `discord_reminders` posts to a channel and needs `channel_id`/`channel_name` from the shop's Discord integration; `lark_reminders` posts to the shop's connected Lark group; `chat_reminders` lands as campaign-chat system messages with `destination: \"channel\" | \"dm\"`. Each item needs `days_before` (integer ≥ 1) and `message` (blank-message rows are dropped). Messages support variables — expand **reminder message variables** below."
                  },
                  "lark_reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "\"N days before the end\" nudges over four channels. `reminders` goes out via SMS/email; `discord_reminders` posts to a channel and needs `channel_id`/`channel_name` from the shop's Discord integration; `lark_reminders` posts to the shop's connected Lark group; `chat_reminders` lands as campaign-chat system messages with `destination: \"channel\" | \"dm\"`. Each item needs `days_before` (integer ≥ 1) and `message` (blank-message rows are dropped). Messages support variables — expand **reminder message variables** below."
                  },
                  "chat_reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "destination": {
                        "type": "string",
                        "description": "\"channel\" | \"dm\""
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "\"N days before the end\" nudges over four channels. `reminders` goes out via SMS/email; `discord_reminders` posts to a channel and needs `channel_id`/`channel_name` from the shop's Discord integration; `lark_reminders` posts to the shop's connected Lark group; `chat_reminders` lands as campaign-chat system messages with `destination: \"channel\" | \"dm\"`. Each item needs `days_before` (integer ≥ 1) and `message` (blank-message rows are dropped). Messages support variables — expand **reminder message variables** below."
                  },
                  "status": {
                    "type": "string",
                    "description": "\"active\" (default) | \"paused\""
                  },
                  "require_discord_join": {
                    "type": "boolean",
                    "description": "Creators may only join once they've linked a Discord account that is a **member of the shop's server** — checked live at join time on the creators platform. Needs the shop's Discord integration connected."
                  },
                  "discord": {
                    "type": "object",
                    "properties": {
                      "assign_roles": {
                        "type": "boolean"
                      },
                      "roles": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "role_id": {
                              "type": "string"
                            },
                            "role_name": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "channel_enabled": {
                        "type": "boolean"
                      },
                      "channel_id": {
                        "type": "string"
                      },
                      "channel_name": {
                        "type": "string"
                      },
                      "dm_enabled": {
                        "type": "boolean"
                      },
                      "dm_message": {
                        "type": "string"
                      }
                    },
                    "description": "Per-campaign **Discord onboarding**: what a creator's Discord account gets once they're actually in the campaign (applied at join when auto-approving, at approval time when `require_approval` is on; every action is best-effort and never blocks a join). `assign_roles` + `roles: [{ \"role_id\", \"role_name\" }]` grants guild roles; `channel_enabled` + `channel_id` opens a channel (member permission overwrite + link on the success screen); `dm_enabled` + `dm_message` sends a bot DM supporting `[shop_name]`, `[campaign_name]`, `[campaign_link]`. Role/channel ids come from the dashboard's Community → Discord page."
                  },
                  "chat": {
                    "type": "object",
                    "properties": {
                      "channel_enabled": {
                        "type": "boolean"
                      },
                      "channel_posting_policy": {
                        "type": "string",
                        "description": "\"open\" | \"brand_only\""
                      },
                      "participant_status": {
                        "type": "string",
                        "description": "\"dm\" | \"off\" — approved/rejected cards"
                      },
                      "payouts": {
                        "type": "string",
                        "description": "\"dm\" | \"off\" — payment-sent cards"
                      },
                      "winners": {
                        "type": "string",
                        "description": "\"dm\" | \"off\" — winner cards on completion"
                      }
                    },
                    "description": "Community-chat block: `channel_enabled` auto-creates the campaign chat channel, `channel_posting_policy` (`open` | `brand_only`) is applied when it's first created, and `participant_status` / `payouts` / `winners` (`dm` | `off`) route the lifecycle system cards. **Omit the block entirely to leave campaign chat off** (legacy behavior); when present, unset fields default to the dashboard's all-on defaults."
                  },
                  "start_date_type": {
                    "type": "string",
                    "description": "Retainer schedule mode — expand **retainer schedule modes** below. Only persisted for retainers and contests; contests support `fixed`/`recurring` only."
                  },
                  "is_recurring": {
                    "type": "boolean",
                    "description": "rolling periods (retainer/contest)"
                  },
                  "recurrence_period": {
                    "type": "string",
                    "description": "required when is_recurring"
                  },
                  "max_periods": {
                    "type": "number",
                    "description": "optional recurring cap"
                  },
                  "duration_days": {
                    "type": "integer",
                    "description": "Retainer-only. `duration_days` (dynamic, default `30`) is each creator's personal period length. `creator_custom_settings` sets per-creator deals — entries need `creator_handle` (or `creator_handles: [...]` to fan one deal out to several creators), `videos_required`, and `payout_amount`; incomplete entries are dropped and handles are cleaned of a leading `@`. `negotiation_enabled` lets creators propose a custom payout at join time. `is_private` hides rates and blocks joining except for `private_allowed_handles` (creators with a personalized deal are always allowed)."
                  },
                  "creator_custom_settings": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "creator_handle": {
                          "type": "string"
                        },
                        "videos_required": {
                          "type": "number"
                        },
                        "payout_amount": {
                          "type": "number"
                        }
                      }
                    },
                    "description": "Retainer-only. `duration_days` (dynamic, default `30`) is each creator's personal period length. `creator_custom_settings` sets per-creator deals — entries need `creator_handle` (or `creator_handles: [...]` to fan one deal out to several creators), `videos_required`, and `payout_amount`; incomplete entries are dropped and handles are cleaned of a leading `@`. `negotiation_enabled` lets creators propose a custom payout at join time. `is_private` hides rates and blocks joining except for `private_allowed_handles` (creators with a personalized deal are always allowed)."
                  },
                  "negotiation_enabled": {
                    "type": "boolean",
                    "description": "Retainer-only. `duration_days` (dynamic, default `30`) is each creator's personal period length. `creator_custom_settings` sets per-creator deals — entries need `creator_handle` (or `creator_handles: [...]` to fan one deal out to several creators), `videos_required`, and `payout_amount`; incomplete entries are dropped and handles are cleaned of a leading `@`. `negotiation_enabled` lets creators propose a custom payout at join time. `is_private` hides rates and blocks joining except for `private_allowed_handles` (creators with a personalized deal are always allowed)."
                  },
                  "is_private": {
                    "type": "boolean",
                    "description": "Retainer-only. `duration_days` (dynamic, default `30`) is each creator's personal period length. `creator_custom_settings` sets per-creator deals — entries need `creator_handle` (or `creator_handles: [...]` to fan one deal out to several creators), `videos_required`, and `payout_amount`; incomplete entries are dropped and handles are cleaned of a leading `@`. `negotiation_enabled` lets creators propose a custom payout at join time. `is_private` hides rates and blocks joining except for `private_allowed_handles` (creators with a personalized deal are always allowed)."
                  },
                  "private_allowed_handles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "bingo": {
                    "type": "object",
                    "properties": {
                      "grid_size": {
                        "type": "number"
                      },
                      "cells": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "field_type": {
                              "type": "string"
                            },
                            "value_x": {
                              "type": "number"
                            }
                          }
                        }
                      }
                    },
                    "description": "Bingo only: `{ \"grid_size\": 3 | 4, \"cells\": [...] }` with exactly `grid_size²` cells of `{ \"field_type\", \"value_x\", \"value_y\"? }` — expand **bingo challenge types** below."
                  },
                  "sweepstakes": {
                    "type": "object",
                    "properties": {
                      "point_rules": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "metric": {
                              "type": "string"
                            },
                            "points_per_unit": {
                              "type": "number"
                            }
                          }
                        }
                      }
                    },
                    "description": "Sweepstakes only: `{ \"point_rules\": [{ \"metric\": \"gmv\" | \"views\" | \"posts\", \"points_per_unit\": 1 }] }` — 1-3 rules, unique metrics."
                  },
                  "config_extras": {
                    "type": "object",
                    "properties": {
                      "max_payout_per_creator": {
                        "type": "number"
                      }
                    },
                    "description": "Advanced config overrides merged into the campaign config (snake_case keys, converted server-side) — expand **config_extras keys** below."
                  }
                }
              },
              "example": {
                "title": "Summer Views Race",
                "description": "Post videos, earn from the pool.",
                "campaign_type": "race",
                "payout_type": "cash",
                "start_date": "2026-07-01",
                "end_date": "2026-08-01",
                "tiers": [
                  {
                    "level": 1,
                    "payout": 5000,
                    "rate_per_view": 0.003
                  }
                ],
                "content_types": [
                  "video"
                ],
                "progress_metric": "views",
                "timezone": "America/New_York",
                "require_approval": false,
                "budget": 5000,
                "hide_budget_card": false,
                "auto_assign_tiers": true,
                "grace_period": 3,
                "usage_rights": "30-day usage rights on posted content",
                "product_ids": [
                  "1800291847362058192"
                ],
                "guidelines": [
                  {
                    "type": "do",
                    "description": "Show the product in use"
                  }
                ],
                "inspiration_links": [
                  "https://www.tiktok.com/@creator/video/7300000000000000001"
                ],
                "reminders": {
                  "enabled": true,
                  "reminders": [
                    {
                      "days_before": 3,
                      "message": "Only 3 days left, [name]!"
                    }
                  ]
                },
                "discord_reminders": {
                  "enabled": true,
                  "channel_id": "118033...",
                  "channel_name": "campaigns",
                  "reminders": [
                    {
                      "days_before": 1,
                      "message": "Last day to post!"
                    }
                  ]
                },
                "lark_reminders": {
                  "enabled": true,
                  "reminders": [
                    {
                      "days_before": 1,
                      "message": "Last day to post!"
                    }
                  ]
                },
                "chat_reminders": {
                  "enabled": true,
                  "destination": "channel",
                  "reminders": [
                    {
                      "days_before": 2,
                      "message": "2 days left!"
                    }
                  ]
                },
                "status": "active",
                "require_discord_join": false,
                "discord": {
                  "assign_roles": true,
                  "roles": [
                    {
                      "role_id": "118044...",
                      "role_name": "Creator"
                    }
                  ],
                  "channel_enabled": true,
                  "channel_id": "118033...",
                  "channel_name": "campaign-chat",
                  "dm_enabled": true,
                  "dm_message": "Welcome to [campaign_name]! Details: [campaign_link]"
                },
                "chat": {
                  "channel_enabled": true,
                  "channel_posting_policy": "brand_only",
                  "participant_status": "dm",
                  "payouts": "dm",
                  "winners": "dm"
                },
                "start_date_type": "fixed",
                "is_recurring": false,
                "recurrence_period": "weekly",
                "max_periods": 8,
                "duration_days": 30,
                "creator_custom_settings": [
                  {
                    "creator_handle": "alice",
                    "videos_required": 4,
                    "payout_amount": 200
                  }
                ],
                "negotiation_enabled": false,
                "is_private": false,
                "private_allowed_handles": [
                  "alice",
                  "bob"
                ],
                "bingo": {
                  "grid_size": 3,
                  "cells": [
                    {
                      "field_type": "total_gmv_above",
                      "value_x": 100
                    }
                  ]
                },
                "sweepstakes": {
                  "point_rules": [
                    {
                      "metric": "gmv",
                      "points_per_unit": 1
                    }
                  ]
                },
                "config_extras": {
                  "max_payout_per_creator": 500
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Response 201",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string"
                        },
                        "share_link": {
                          "type": "string",
                          "description": "The public join URL. Reference it in an automation DM/invite message to invite creators."
                        },
                        "status": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "Response_201": {
                    "summary": "Response 201",
                    "value": {
                      "data": {
                        "message": "Campaign created.",
                        "campaign_id": "6a61ef6bcc6388012e941c8f",
                        "url": "wpasve",
                        "share_link": "https://creators.cruva.com/wpasve",
                        "status": "active"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "validation error (the specific field is named in the message)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "plan below Scale, or 100-campaign cap reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "plan below Scale, or 100-campaign cap reached",
                    "value": {
                      "error": "Community campaigns require the Scale plan"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "duplicate title; a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "duplicate title",
                    "value": {
                      "error": "Campaign already exists, choose a different name."
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/update": {
      "post": {
        "operationId": "communityCampaignsUpdate",
        "summary": "Community - Update Campaign",
        "description": "Partially update a campaign — only the fields you send change. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.\n\n**Schedule lock:** once any creator has joined a retainer or contest, its schedule anchor (`start_date`, `start_date_type`, `is_recurring`, `recurrence_period`, and `end_date` for recurring campaigns) is pinned — those fields are silently dropped from the update and the response carries `schedule_locked: true`. **Auto-reactivation:** moving `end_date` into the future on a `completed` campaign sets it back to `active`.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaigns-update"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/update"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign to update. Obtain from `/community/campaigns/list`."
                  },
                  "title": {
                    "type": "string",
                    "description": "Optional. New title — must stay unique within the shop (409 on duplicate)."
                  },
                  "description": {
                    "type": "string"
                  },
                  "end_date": {
                    "type": "string",
                    "format": "date"
                  },
                  "tiers": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "level": {
                          "type": "number"
                        },
                        "payout": {
                          "type": "number"
                        },
                        "rate_per_view": {
                          "type": "number"
                        }
                      }
                    },
                    "description": "Optional. Full replacement of the tier list (same per-type shape and validation as [create](https://cruva.com/docs/api#community-campaigns-create)). On contest/leaderboard/sweepstakes/bingo, replacing tiers also **re-derives `payout_type`** from what the new tiers carry (cash / prize / both), same as every dashboard save."
                  },
                  "budget": {
                    "type": "number"
                  },
                  "hide_budget_card": {
                    "type": "boolean",
                    "description": "Optional toggles — same semantics as create: hide the spend figure from creators; contests' automatic tier assignment; the Discord-membership join gate."
                  },
                  "auto_assign_tiers": {
                    "type": "boolean",
                    "description": "Optional toggles — same semantics as create: hide the spend figure from creators; contests' automatic tier assignment; the Discord-membership join gate."
                  },
                  "require_approval": {
                    "type": "boolean"
                  },
                  "require_discord_join": {
                    "type": "boolean",
                    "description": "Optional toggles — same semantics as create: hide the spend figure from creators; contests' automatic tier assignment; the Discord-membership join gate."
                  },
                  "content_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Optional. Replacement content kinds — any combination of `video`, `LIVE`, `photo`; same per-type rules as create. The legacy `content_type` mirror is kept in lockstep automatically."
                  },
                  "usage_rights": {
                    "type": "string"
                  },
                  "guidelines": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "description": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "inspiration_links": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "max_periods": {
                    "type": "number"
                  },
                  "duration_days": {
                    "type": "integer"
                  },
                  "creator_custom_settings": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "creator_handle": {
                          "type": "string"
                        },
                        "videos_required": {
                          "type": "number"
                        },
                        "payout_amount": {
                          "type": "number"
                        }
                      }
                    },
                    "description": "Optional. Full replacement of the retainer per-creator deals (pass `[]` to clear). Same shape and cleanup rules as create."
                  },
                  "private_allowed_handles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Optional. Full replacement of a private retainer's allowlist."
                  },
                  "discord": {
                    "type": "object",
                    "properties": {
                      "assign_roles": {
                        "type": "boolean"
                      },
                      "roles": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "role_id": {
                              "type": "string"
                            },
                            "role_name": {
                              "type": "string"
                            }
                          }
                        }
                      },
                      "dm_enabled": {
                        "type": "boolean"
                      },
                      "dm_message": {
                        "type": "string"
                      }
                    },
                    "description": "Optional. Full replacement of the per-campaign Discord onboarding block and the campaign-chat block — same shapes and validation as [create](https://cruva.com/docs/api#community-campaigns-create)."
                  },
                  "chat": {
                    "type": "object",
                    "properties": {
                      "channel_enabled": {
                        "type": "boolean"
                      },
                      "channel_posting_policy": {
                        "type": "string"
                      },
                      "participant_status": {
                        "type": "string"
                      },
                      "payouts": {
                        "type": "string"
                      },
                      "winners": {
                        "type": "string"
                      }
                    },
                    "description": "Optional. Full replacement of the per-campaign Discord onboarding block and the campaign-chat block — same shapes and validation as [create](https://cruva.com/docs/api#community-campaigns-create)."
                  },
                  "reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "Optional. Full replacement of a reminder channel's config — same shapes, validation, and message variables as create."
                  },
                  "discord_reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "channel_id": {
                        "type": "string"
                      },
                      "channel_name": {
                        "type": "string"
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "Optional. Full replacement of a reminder channel's config — same shapes, validation, and message variables as create."
                  },
                  "lark_reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "Optional. Full replacement of a reminder channel's config — same shapes, validation, and message variables as create."
                  },
                  "chat_reminders": {
                    "type": "object",
                    "properties": {
                      "enabled": {
                        "type": "boolean"
                      },
                      "destination": {
                        "type": "string"
                      },
                      "reminders": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "days_before": {
                              "type": "number"
                            },
                            "message": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "description": "Optional. Full replacement of a reminder channel's config — same shapes, validation, and message variables as create."
                  },
                  "config_updates": {
                    "type": "object",
                    "properties": {
                      "winner_message": {
                        "type": "string"
                      }
                    },
                    "description": "Optional. Arbitrary config-field overrides (snake_case keys, converted server-side), applied as `config.<key>` — same vocabulary as create's `config_extras`."
                  },
                  "bingo": {
                    "description": "Optional. Full replacement of the type-specific config, re-validated. A drawn sweepstakes `winner` is never overwritten from the API."
                  },
                  "sweepstakes": {
                    "description": "Optional. Full replacement of the type-specific config, re-validated. A drawn sweepstakes `winner` is never overwritten from the API."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "title": "Summer Views Race v2",
                "description": "Updated description",
                "end_date": "2026-09-01",
                "tiers": [
                  {
                    "level": 1,
                    "payout": 7500,
                    "rate_per_view": 0.003
                  }
                ],
                "budget": 7500,
                "hide_budget_card": true,
                "auto_assign_tiers": false,
                "require_approval": true,
                "require_discord_join": true,
                "content_types": [
                  "video",
                  "photo"
                ],
                "usage_rights": "60-day usage rights",
                "guidelines": [
                  {
                    "type": "dont",
                    "description": "No competitor products"
                  }
                ],
                "inspiration_links": [
                  "https://www.tiktok.com/@creator/video/7300000000000000001"
                ],
                "max_periods": 12,
                "duration_days": 45,
                "creator_custom_settings": [
                  {
                    "creator_handle": "alice",
                    "videos_required": 4,
                    "payout_amount": 200
                  }
                ],
                "private_allowed_handles": [
                  "alice",
                  "bob"
                ],
                "discord": {
                  "assign_roles": true,
                  "roles": [
                    {
                      "role_id": "118044...",
                      "role_name": "Creator"
                    }
                  ],
                  "dm_enabled": true,
                  "dm_message": "Welcome to [campaign_name]!"
                },
                "chat": {
                  "channel_enabled": true,
                  "channel_posting_policy": "open",
                  "participant_status": "dm",
                  "payouts": "dm",
                  "winners": "dm"
                },
                "reminders": {
                  "enabled": true,
                  "reminders": [
                    {
                      "days_before": 3,
                      "message": "3 days left, [name]!"
                    }
                  ]
                },
                "discord_reminders": {
                  "enabled": true,
                  "channel_id": "118033...",
                  "channel_name": "campaigns",
                  "reminders": [
                    {
                      "days_before": 1,
                      "message": "Last day!"
                    }
                  ]
                },
                "lark_reminders": {
                  "enabled": true,
                  "reminders": [
                    {
                      "days_before": 1,
                      "message": "Last day!"
                    }
                  ]
                },
                "chat_reminders": {
                  "enabled": true,
                  "destination": "channel",
                  "reminders": [
                    {
                      "days_before": 2,
                      "message": "2 days left!"
                    }
                  ]
                },
                "config_updates": {
                  "winner_message": "You won! Check your email."
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string"
                        },
                        "schedule_locked": {
                          "type": "boolean"
                        },
                        "note": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Campaign updated.",
                        "campaign_id": "6a61ef6bcc6388012e941c8f"
                      }
                    }
                  },
                  "Response_when_schedule_fields_were_pinned": {
                    "summary": "Response when schedule fields were pinned",
                    "value": {
                      "data": {
                        "message": "Campaign updated.",
                        "campaign_id": "6a61ef6bcc6388012e941c8f",
                        "schedule_locked": true,
                        "note": "Schedule fields were not changed: creators have already joined."
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/set_status": {
      "post": {
        "operationId": "communityCampaignsSetStatus",
        "summary": "Community - Set Campaign Status",
        "description": "Set a campaign's lifecycle status. `paused` hides it from joining; `completed` freezes it — required before leaderboard payouts are allowed.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaigns-set-status"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/set_status"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign to update. Obtain from `/community/campaigns/list`."
                  },
                  "status": {
                    "type": "string",
                    "description": "One of `active`, `paused`, or `completed`."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "status": "completed"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Campaign status set to completed"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/delete": {
      "delete": {
        "operationId": "communityCampaignsDelete",
        "summary": "Community - Delete Campaign",
        "description": "Permanently delete a campaign. This **cascades**: participant records, tracked videos, and progress rows are deleted from the engagement system first; only if that succeeds is the campaign document removed. It cannot be undone — prefer `set_status` with `completed` or `paused` unless you truly want it gone. The body is parsed with `request.get_json(silent=True)` so a missing or unparseable body returns a clean `400` instead of `415`. Optionally idempotent — see the [Idempotency](https://cruva.com/docs/api#idempotency-about) section.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaigns-delete"
        },
        "security": [
          {
            "apiKey": [
              "DELETE /community/campaigns/delete"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign to delete. Obtain from `/community/campaigns/list`."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Campaign deleted.",
                        "campaign_id": "6a61ef6bcc6388012e941c8f"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "missing or malformed campaign_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "missing or malformed campaign_id",
                    "value": {
                      "error": "Invalid campaign_id"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "not found, or not owned by this shop",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "not found, or not owned by this shop",
                    "value": {
                      "error": "Campaign not found"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "a request with the same `Idempotency-Key` is still in flight (retry after it completes)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "engagement-system cascade failed; the campaign was NOT deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "engagement-system cascade failed; the campaign was NOT deleted",
                    "value": {
                      "error": "Failed to delete campaign engagement data"
                    }
                  }
                }
              }
            }
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/participants": {
      "post": {
        "operationId": "communityParticipants",
        "summary": "Community - List Participants",
        "description": "List the creators in a campaign with their progress (GMV, posts, views), participation status, payment state, and — on cash campaigns — **what each creator is currently owed**. `amount_owed` is computed by the campaign's own payout rules (tiers, per-creator deals, caps) and already excludes paid participants; it is exactly what [/community/payouts/authorize](https://cruva.com/docs/api#community-payouts-authorize) will pay. Use `search` to find one creator by handle, `status: \"pending\"` to pull the approval queue on invite-only campaigns.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-participants"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/participants"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign. Obtain from `/community/campaigns/list`."
                  },
                  "page": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max `100`."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max `100`."
                  },
                  "status": {
                    "type": "string",
                    "description": "Optional filter. One of `pending`, `approved`, `rejected`, `under_review`, `removed`."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match on the creator's handle (a leading `@` is ignored). Search results return the core fields (no `views`/`metric_value`)."
                  },
                  "period_id": {
                    "type": "string",
                    "description": "Optional, recurring retainers only — `\"<campaign_id>_<period>\"` scopes results (and the owed calculation) to one period."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "page": 1,
                "page_size": 25,
                "status": "approved",
                "search": "sassy",
                "period_id": "6a61ef6bcc6388012e941c8f_2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "participants": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "creator_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "status": {
                                "type": "string"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "post_count": {
                                "type": "integer"
                              },
                              "live_count": {
                                "type": "integer"
                              },
                              "views": {
                                "type": "number"
                              },
                              "metric_value": {
                                "type": "number"
                              },
                              "joined_at": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "is_paid": {
                                "type": "boolean"
                              },
                              "tier": {},
                              "amount_owed": {
                                "type": "number"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "progress_metric": {
                          "type": "string"
                        },
                        "counts": {
                          "type": "object",
                          "properties": {
                            "approved": {
                              "type": "number"
                            },
                            "pending": {
                              "type": "number"
                            },
                            "rejected": {
                              "type": "number"
                            },
                            "under_review": {
                              "type": "number"
                            }
                          }
                        },
                        "approved_totals": {
                          "type": "object",
                          "properties": {
                            "gmv": {
                              "type": "number"
                            },
                            "posts": {
                              "type": "number"
                            },
                            "views": {
                              "type": "number"
                            }
                          }
                        },
                        "amount_owed_total": {
                          "type": "number",
                          "description": "Campaign-wide outstanding total, and — when owed amounts are `0` for a structural reason — why (e.g. `\"Campaign is not finished yet\"`, `\"Leaderboard payouts become available once the campaign is completed\"`)."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "participants": [
                          {
                            "creator_id": "3f6b2c1e-9a47-4d20-b8c3-2f1a9d7e6c05",
                            "handle": "sassykittypaw",
                            "status": "approved",
                            "gmv": 1197.33,
                            "post_count": 14,
                            "live_count": 0,
                            "views": 238358,
                            "metric_value": 238358,
                            "joined_at": "2026-06-14T18:02:11+00:00",
                            "is_paid": false,
                            "tier": null,
                            "amount_owed": 50
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "has_more": true,
                        "progress_metric": "views",
                        "counts": {
                          "approved": 37,
                          "pending": 5,
                          "rejected": 2,
                          "under_review": 0
                        },
                        "approved_totals": {
                          "gmv": 13397.42,
                          "posts": 6154,
                          "views": 4714573
                        },
                        "amount_owed_total": 160
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/participants/set_status": {
      "post": {
        "operationId": "communityParticipantsSetStatus",
        "summary": "Community - Approve / Reject Participant",
        "description": "Change a creator's participation status in a campaign — the approval workflow for invite-only campaigns (`require_approval: true`). Approving increments the campaign's joined count. `removed` kicks a creator out of the **latest period** of a recurring retainer and requires a `period_id`.\n\n**Note:** approval/rejection SMS notifications are only sent when acting from the dashboard — API status changes do not text the creator.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-participants-set-status"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/participants/set_status"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign. Obtain from `/community/campaigns/list`."
                  },
                  "creator_id": {
                    "type": "string",
                    "description": "The participant. Obtain from `/community/campaigns/participants`."
                  },
                  "status": {
                    "type": "string",
                    "description": "One of `approved`, `rejected`, `pending`, `under_review`, `removed`."
                  },
                  "period_id": {
                    "type": "string",
                    "description": "`\"<campaign_id>_<period>\"` — required for `removed` on recurring retainers."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "creator_id": "3f6b2c1e-9a47-4d20-b8c3-2f1a9d7e6c05",
                "status": "approved"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Creator status updated",
                        "status": "approved"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid status, or missing period for \"removed\"",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "invalid status, or missing period for \"removed\"",
                    "value": {
                      "error": "status must be one of: pending, approved, rejected, under_review, removed"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "no engagement row for this creator in this campaign",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "no engagement row for this creator in this campaign",
                    "value": {
                      "error": "Engagement not found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/videos": {
      "post": {
        "operationId": "communityCampaignVideos",
        "summary": "Community - List Campaign Videos",
        "description": "List the videos posted in a campaign, with per-video stats. Sortable and filterable by creator, GMV, and post date.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaign-videos"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/videos"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign. Obtain from `/community/campaigns/list`."
                  },
                  "page": {
                    "type": "integer"
                  },
                  "page_size": {
                    "type": "integer"
                  },
                  "handle": {
                    "type": "string",
                    "description": "Optional filters."
                  },
                  "min_gmv": {
                    "type": "number",
                    "description": "Optional filters."
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "One of `gmv`, `view_count`, `like_count`, `comment_count`, `units_sold`, `ctr`, `post_time`. Default `gmv`."
                  },
                  "sort_direction": {
                    "type": "string"
                  },
                  "date_from": {
                    "type": "string",
                    "format": "date",
                    "description": "Optional ISO-date bounds on post time."
                  },
                  "date_to": {
                    "type": "string",
                    "format": "date",
                    "description": "Optional ISO-date bounds on post time."
                  },
                  "min_views": {
                    "type": "number",
                    "description": "Optional filters."
                  },
                  "product_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Optional filters."
                  },
                  "disqualified": {
                    "description": "Optional filters."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "page": 1,
                "page_size": 25,
                "handle": "",
                "min_gmv": 10,
                "sort_by": "gmv",
                "sort_direction": "desc",
                "date_from": "2026-07-01",
                "date_to": "2026-07-23"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "videos": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "video_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "title": {
                                "type": "string"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "view_count": {
                                "type": "integer"
                              },
                              "like_count": {
                                "type": "integer"
                              },
                              "comment_count": {
                                "type": "integer"
                              },
                              "units_sold": {
                                "type": "number"
                              },
                              "post_time": {
                                "type": "string"
                              },
                              "disqualified": {
                                "type": "boolean"
                              },
                              "products": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "url": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "videos": [
                          {
                            "video_id": "7523456789012345678",
                            "handle": "babypinkcashmere",
                            "title": "my new favorite find",
                            "gmv": 4247.51,
                            "view_count": 1318277,
                            "like_count": 88213,
                            "comment_count": 1204,
                            "units_sold": 312,
                            "post_time": "07/03/2026",
                            "disqualified": false,
                            "products": [
                              "1800291847362058192"
                            ],
                            "url": "https://tiktok.com/@babypinkcashmere/video/7523456789012345678"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 6154,
                        "has_more": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/campaigns/lives": {
      "post": {
        "operationId": "communityCampaignLives",
        "summary": "Community - List Campaign LIVEs",
        "description": "List the LIVE streams in a campaign, with per-live stats and campaign totals.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-campaign-lives"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/campaigns/lives"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign. Obtain from `/community/campaigns/list`."
                  },
                  "page": {
                    "type": "integer"
                  },
                  "page_size": {
                    "type": "integer"
                  },
                  "sort_by": {
                    "type": "string",
                    "description": "One of `gmv`, `views`, `likes`, `comments`, `units_sold`, `duration`, `start_time`. Default `gmv`."
                  },
                  "handle": {
                    "type": "string",
                    "description": "Optional filters."
                  },
                  "min_gmv": {
                    "type": "number",
                    "description": "Optional filters."
                  },
                  "date_from": {
                    "type": "string",
                    "format": "date",
                    "description": "Optional filters."
                  },
                  "date_to": {
                    "type": "string",
                    "format": "date",
                    "description": "Optional filters."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "page": 1,
                "page_size": 25,
                "sort_by": "gmv"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "lives": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "live_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "title": {
                                "type": "string"
                              },
                              "start_time": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "duration": {
                                "type": "number"
                              },
                              "views": {
                                "type": "number"
                              },
                              "likes": {
                                "type": "number"
                              },
                              "comments": {
                                "type": "number"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "units_sold": {
                                "type": "number"
                              },
                              "products": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "url": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "total_count": {
                          "type": "integer"
                        },
                        "total_gmv": {
                          "type": "number"
                        },
                        "total_views": {
                          "type": "number"
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "lives": [
                          {
                            "live_id": "7519876543210987654",
                            "handle": "sassykittypaw",
                            "title": "Friday night deals!",
                            "start_time": "2026-07-18T01:00:00+00:00",
                            "duration": 7215,
                            "views": 48210,
                            "likes": 15302,
                            "comments": 2210,
                            "gmv": 1890.4,
                            "units_sold": 145,
                            "products": [
                              "1800291847362058192"
                            ],
                            "url": "https://www.tiktok.com/@sassykittypaw/live/7519876543210987654"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "total_count": 12,
                        "total_gmv": 8123.5,
                        "total_views": 391200,
                        "has_more": false
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/discord/members": {
      "post": {
        "operationId": "communityDiscordMembers",
        "summary": "Community - List Discord Members",
        "description": "List the members of your brand's Discord server and who each one is on TikTok. A member is **linked** when a TikTok handle is attached — either a Cruva creator who connected that Discord account (`link_source: \"cruva\"`, with a `creator_id`), or a handle you attached from the dashboard's Discord page via the Link button or a CSV upload (`link_source: \"brand\"`). Unlinked members are people in your server nobody has identified yet — the natural list to invite to Cruva. Bots are excluded. The roster is a snapshot kept in sync by Cruva (`synced_at` tells you how fresh); changes made from the dashboard apply immediately. Requires Discord to be connected on the shop.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-discord-members"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/discord/members"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "page": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max `100`. Sorted by server join date, newest first."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Optional. Defaults `1` / `25`, max `100`. Sorted by server join date, newest first."
                  },
                  "linked": {
                    "type": "boolean",
                    "description": "Optional. `true` → only members with a TikTok handle attached; `false` → only members without one; omit for everyone."
                  },
                  "search": {
                    "type": "string",
                    "description": "Optional. Case-insensitive substring match on the Discord username, display name, or linked TikTok handle (a leading `@` is ignored)."
                  },
                  "format": {
                    "type": "string",
                    "description": "Optional. `csv` returns a presigned download link for the **whole filtered list** (paging is ignored) instead of a page of JSON."
                  }
                }
              },
              "example": {
                "page": 1,
                "page_size": 25,
                "linked": true,
                "search": "alicia",
                "format": "json"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "members": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "discord_user_id": {
                                "type": "string"
                              },
                              "username": {
                                "type": "string"
                              },
                              "display_name": {
                                "type": "string"
                              },
                              "avatar_url": {
                                "type": "string"
                              },
                              "role_ids": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "joined_at": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "is_booster": {
                                "type": "boolean"
                              },
                              "linked": {
                                "type": "boolean"
                              },
                              "tiktok_handle": {
                                "type": "string"
                              },
                              "link_source": {
                                "type": "string"
                              },
                              "creator_id": {
                                "type": [
                                  "string",
                                  "null"
                                ]
                              }
                            }
                          }
                        },
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "total_count": {
                          "type": "integer",
                          "description": "Members matching the current `linked` / `search` filter."
                        },
                        "counts": {
                          "type": "object",
                          "properties": {
                            "total": {
                              "type": "number"
                            },
                            "linked": {
                              "type": "number"
                            },
                            "unlinked": {
                              "type": "number"
                            }
                          },
                          "description": "Server-wide totals regardless of filter: `total`, `linked`, `unlinked` (bots excluded)."
                        },
                        "synced_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "When the roster snapshot was last refreshed from Discord."
                        },
                        "csv": {
                          "type": "object",
                          "properties": {
                            "url": {
                              "type": "string"
                            },
                            "rows": {
                              "type": "number"
                            },
                            "filename": {
                              "type": "string"
                            },
                            "expires_in": {
                              "type": "number"
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "members": [
                          {
                            "discord_user_id": "1092550752695754803",
                            "username": "aliciaborchardt",
                            "display_name": "Alicia",
                            "avatar_url": "https://cdn.discordapp.com/avatars/1092550752695754803/a1b2c3.png",
                            "role_ids": [
                              "1516114048226299907"
                            ],
                            "joined_at": "2026-05-22T13:52:00+00:00",
                            "is_booster": false,
                            "linked": true,
                            "tiktok_handle": "aliciaborchardtyt",
                            "link_source": "brand",
                            "creator_id": null
                          },
                          {
                            "discord_user_id": "1092550752695754804",
                            "username": "samantha_nicolex4",
                            "display_name": "Sam",
                            "avatar_url": "https://cdn.discordapp.com/embed/avatars/2.png",
                            "role_ids": [],
                            "joined_at": "2025-11-19T20:38:00+00:00",
                            "is_booster": true,
                            "linked": true,
                            "tiktok_handle": "samantha_nicolex4",
                            "link_source": "cruva",
                            "creator_id": "3f6b2c1e-9a47-4d20-b8c3-2f1a9d7e6c05"
                          }
                        ],
                        "page": 1,
                        "page_size": 25,
                        "has_more": true,
                        "total_count": 1054,
                        "counts": {
                          "total": 5016,
                          "linked": 1054,
                          "unlinked": 3962
                        },
                        "synced_at": "2026-09-30T05:20:22+00:00"
                      }
                    }
                  },
                  "CSV_mode": {
                    "summary": "CSV mode",
                    "value": {
                      "data": {
                        "csv": {
                          "url": "https://cruva-exports.s3.amazonaws.com/.../discord_members_<shop_id>.csv?...",
                          "rows": 1054,
                          "filename": "discord_members_<shop_id>.csv",
                          "expires_in": 3600
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "the shop has no Discord server connected; linked must be a boolean",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "the shop has no Discord server connected",
                    "value": {
                      "error": "Discord is not connected for this shop"
                    }
                  },
                  "error_2": {
                    "summary": "linked must be a boolean",
                    "value": {
                      "error": "linked must be true or false"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/stats": {
      "post": {
        "operationId": "communityStats",
        "summary": "Community - Stats",
        "description": "Per-day time series for the community program: earnings (GMV), views, videos posted, and payout spend. GMV includes both video GMV and campaign-attributed LIVE GMV. Scope to a single campaign, all campaigns, or all retainers. Series are gap-filled — quiet days appear with `0`.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-stats"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/stats"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "scope": {
                    "type": "string",
                    "description": "One of `campaign` (one campaign — requires `campaign_id`), `campaigns` (all, default), or `retainers`."
                  },
                  "campaign_id": {
                    "type": "string",
                    "description": "Required when `scope` is `campaign`."
                  },
                  "date_from": {
                    "type": "string",
                    "format": "date",
                    "description": "Optional `YYYY-MM-DD` window, max 366 days. Defaults to the last 30 days."
                  },
                  "date_to": {
                    "type": "string",
                    "format": "date",
                    "description": "Optional `YYYY-MM-DD` window, max 366 days. Defaults to the last 30 days."
                  }
                }
              },
              "example": {
                "scope": "campaign",
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "date_from": "2026-06-23",
                "date_to": "2026-07-23"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "scope": {
                          "type": "string"
                        },
                        "campaign_id": {
                          "type": "string"
                        },
                        "date_from": {
                          "type": "string",
                          "format": "date"
                        },
                        "date_to": {
                          "type": "string",
                          "format": "date"
                        },
                        "series": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string"
                              },
                              "stats": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "day": {
                                      "type": "string",
                                      "format": "date"
                                    },
                                    "value": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "total": {
                                "type": "number",
                                "description": "Window total. For `videos_per_day` this is the **distinct** video count across the window (a video active on multiple days counts once), so it can be less than the sum of the daily points."
                              }
                            }
                          },
                          "description": "Four series: `gmv_per_day` (video + LIVE GMV), `views_per_day`, `videos_per_day`, `spend_per_day` (creator payouts)."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "scope": "campaign",
                        "campaign_id": "6a61ef6bcc6388012e941c8f",
                        "date_from": "2026-06-23",
                        "date_to": "2026-07-23",
                        "series": [
                          {
                            "type": "gmv_per_day",
                            "stats": [
                              {
                                "day": "2026-06-23",
                                "value": 27.68
                              },
                              {
                                "day": "2026-06-24",
                                "value": 59.93
                              }
                            ],
                            "total": 13397.42
                          },
                          {
                            "type": "views_per_day",
                            "stats": [],
                            "total": 4714573
                          },
                          {
                            "type": "videos_per_day",
                            "stats": [],
                            "total": 5716
                          },
                          {
                            "type": "spend_per_day",
                            "stats": [],
                            "total": 1200
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/balance": {
      "post": {
        "operationId": "communityBalance",
        "summary": "Community - Balance",
        "description": "Read the shop's community balance — the funds available to pay creators, in the shop's local currency. Computed live as top-ups minus payouts already sent; there is no stored balance. Payouts via `/community/payouts/authorize` are rejected when they exceed this balance. Funds are added from the dashboard (Community → Payments).",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-balance"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/balance"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "balance": {
                          "type": "number",
                          "description": "Spendable funds: `max(0, total_charges - total_transfers)`, in the shop's local currency."
                        },
                        "total_charges": {
                          "type": "number",
                          "description": "Sum of completed balance top-ups."
                        },
                        "total_transfers": {
                          "type": "number",
                          "description": "Sum of creator payouts already sent (net of reversals)."
                        },
                        "charges_count": {
                          "type": "integer"
                        },
                        "transfers_count": {
                          "type": "integer"
                        },
                        "currency": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "balance": 3800,
                        "total_charges": 5000,
                        "total_transfers": 1200,
                        "charges_count": 2,
                        "transfers_count": 6,
                        "currency": "usd"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/payouts/authorize": {
      "post": {
        "operationId": "communityPayoutsAuthorize",
        "summary": "Community - Authorize Payout",
        "description": "**Moves real money.** Pays a creator **exactly what they are owed** for a campaign — the server computes the amount from the campaign's own payout rules (the `amount_owed` shown per creator on [/community/campaigns/participants](https://cruva.com/docs/api#community-participants)), sends a Stripe transfer to the creator's connected account in the shop's local currency, and marks the participant paid. You never choose the amount: partial or inflated payouts are impossible through this endpoint.\n\nGuarded by: nothing-owed rejection (including already-paid creators), the shop's community balance, the creator's Stripe onboarding state, and a once-per-**(campaign, creator, period)** idempotency check — repeating the call for the same trio returns `400 already paid` instead of double-paying.\n\n**When money becomes payable:** races and bingo accrue live; leaderboards require the campaign to be `completed` (via `/community/campaigns/set_status`); everything else pays after the campaign/period ends plus the grace window. For payments made outside the platform, use `/community/payouts/manual`.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-payouts-authorize"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/payouts/authorize"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign the payout is for. Obtain from `/community/campaigns/list`."
                  },
                  "creator_id": {
                    "type": "string",
                    "description": "The participant to pay. Obtain from `/community/campaigns/participants` (which also shows their `amount_owed`)."
                  },
                  "creator_handle": {
                    "type": "string",
                    "description": "Optional. Recorded on the transfer for bookkeeping."
                  },
                  "period_id": {
                    "type": "string",
                    "description": "Optional — `\"<campaign_id>_<period>\"` targets a specific recurring-retainer period; defaults to the latest."
                  },
                  "amount": {
                    "type": "number",
                    "description": "**Optional, confirmation only.** If provided it must equal the owed amount or the request is rejected with the correct figure — it never overrides what's paid. Omit it to pay exactly what's owed."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "creator_id": "3f6b2c1e-9a47-4d20-b8c3-2f1a9d7e6c05",
                "creator_handle": "sassykittypaw",
                "period_id": "6a61ef6bcc6388012e941c8f_2",
                "amount": 50
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "transfer_id": {
                          "type": "string"
                        },
                        "amount": {
                          "type": "number",
                          "description": "What was actually paid — the server-computed owed amount."
                        },
                        "currency": {
                          "type": "string"
                        },
                        "period": {
                          "type": "number"
                        },
                        "marked_paid": {
                          "type": "boolean",
                          "description": "Whether the participant was recorded as paid after the transfer. If `false`, the money moved but bookkeeping failed — verify in the dashboard before retrying."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Payout initiated. Balance is deducted when the transfer completes.",
                        "transfer_id": "tr_3RkQ8x2eZvKYlo2C0aB1cD2e",
                        "amount": 50,
                        "currency": "usd",
                        "period": 2,
                        "marked_paid": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "nothing outstanding for this creator (never earned, or already paid); campaign hasn't reached its payout window yet; caller-supplied amount doesn't match the owed amount; balance too low; replay of an already-sent payout; creator's Stripe account not ready; leaderboard still live",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "nothing outstanding for this creator (never earned, or already paid)",
                    "value": {
                      "error": "Nothing is currently owed to this creator for this campaign period"
                    }
                  },
                  "error_2": {
                    "summary": "campaign hasn't reached its payout window yet",
                    "value": {
                      "error": "Campaign is not finished yet"
                    }
                  },
                  "error_3": {
                    "summary": "caller-supplied amount doesn't match the owed amount",
                    "value": {
                      "error": "amount does not match: this creator is owed 50.00. Omit amount to pay exactly what is owed."
                    }
                  },
                  "error_4": {
                    "summary": "balance too low",
                    "value": {
                      "error": "Insufficient balance. Current balance: 120.00 USD"
                    }
                  },
                  "error_5": {
                    "summary": "replay of an already-sent payout",
                    "value": {
                      "error": "This creator has already been paid for this campaign"
                    }
                  },
                  "error_6": {
                    "summary": "creator's Stripe account not ready",
                    "value": {
                      "error": "Creator does not have a Stripe account set up"
                    }
                  },
                  "error_7": {
                    "summary": "leaderboard still live",
                    "value": {
                      "error": "Leaderboard payouts become available once the campaign is completed"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/community/payouts/manual": {
      "post": {
        "operationId": "communityPayoutsManual",
        "summary": "Community - Record Manual Payout",
        "description": "Record that a creator was paid **outside the platform** (PayPal, wire, etc.) — no money moves. Marks the participant paid for the campaign period and adds the amount to the campaign's spend total. Rejected if the participant is already marked paid.\n\nOmit `amount` to record exactly what the campaign says is owed (same calculation as `/community/payouts/authorize`); pass an explicit `amount` only for off-platform deals at a negotiated figure — unlike the Stripe payout, this endpoint accepts one, since it only records history.",
        "tags": [
          "Community"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#community-payouts-manual"
        },
        "security": [
          {
            "apiKey": [
              "POST /community/payouts/manual"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "campaign_id": {
                    "type": "string",
                    "description": "The campaign the payment was for. Obtain from `/community/campaigns/list`."
                  },
                  "creator_id": {
                    "type": "string",
                    "description": "The participant. Obtain from `/community/campaigns/participants`."
                  },
                  "amount": {
                    "type": "number",
                    "description": "Optional. Amount that was paid, in `currency`. Defaults to the creator's outstanding `amount_owed`."
                  },
                  "currency": {
                    "type": "string",
                    "description": "Optional ISO currency code. Defaults to the shop's local currency."
                  },
                  "period_id": {
                    "type": "string",
                    "description": "Optional — `\"<campaign_id>_<period>\"` targets a specific recurring-retainer period; defaults to the latest."
                  }
                }
              },
              "example": {
                "campaign_id": "6a61ef6bcc6388012e941c8f",
                "creator_id": "3f6b2c1e-9a47-4d20-b8c3-2f1a9d7e6c05",
                "amount": 250,
                "currency": "usd",
                "period_id": "6a61ef6bcc6388012e941c8f_2"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        },
                        "amount": {
                          "type": "number"
                        },
                        "currency": {
                          "type": "string"
                        },
                        "period": {
                          "type": "number"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "message": "Manual payout recorded (no money moved).",
                        "amount": 250,
                        "currency": "usd",
                        "period": 2
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "already recorded as paid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "already recorded as paid",
                    "value": {
                      "error": "Engagement already marked as paid"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "no engagement row for this creator in this campaign",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "error_1": {
                    "summary": "no engagement row for this creator in this campaign",
                    "value": {
                      "error": "Engagement not found"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "standard"
      }
    },
    "/affiliate/marketplace/search": {
      "post": {
        "operationId": "socialListeningCreator",
        "summary": "Creator Data",
        "description": "Retrieve detailed creator performance metrics and demographics for a specific creator handle.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Creators"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#social-listening-creator"
        },
        "security": [
          {
            "apiKey": [
              "POST /affiliate/marketplace/search"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "**Note:** The handle must match exactly to avoid data abuse. Fuzzy matching is not supported.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "TikTok Shop market to query. One of `us`, `uk`, `mx`, `es`, `de`, `ie`, `it`, `fr`, `nl`, `pt`, `gr`, `be`, `at`, `pl`, `hu`, `cz`, `br`, `jp`."
                  },
                  "handle": {
                    "type": "string",
                    "description": "Creator's TikTok handle (must match exactly - no fuzzy matching)"
                  }
                }
              },
              "example": {
                "region": "us",
                "handle": "thysamus"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "creator_id": {
                          "type": "string"
                        },
                        "category": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "top_follower_ages": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "handle": {
                          "type": "string"
                        },
                        "nickname": {
                          "type": "string"
                        },
                        "email": {},
                        "follower_cnt": {
                          "type": "integer"
                        },
                        "is_fast_growing": {
                          "type": "boolean"
                        },
                        "med_gmv_revenue_range": {
                          "type": "number"
                        },
                        "units_sold_range": {
                          "type": "number"
                        },
                        "top_follower_gender": {
                          "type": "string"
                        },
                        "video_avg_view_cnt": {
                          "type": "integer"
                        },
                        "video_engagement": {
                          "type": "number"
                        },
                        "spanish": {
                          "type": "boolean"
                        },
                        "post_rate": {
                          "type": "number"
                        },
                        "gender": {
                          "type": "string"
                        },
                        "med_gmv_revenue": {
                          "type": "number",
                          "description": "total GMV earned across the platform in the last 30 days"
                        },
                        "brand_collaborations": {
                          "type": "number"
                        },
                        "gmv_range": {
                          "type": "number"
                        },
                        "race": {
                          "type": "string"
                        },
                        "body_type": {
                          "type": "string"
                        },
                        "economic_status": {
                          "type": "string"
                        },
                        "age": {
                          "type": "string"
                        },
                        "face_visibility": {
                          "type": "string"
                        },
                        "tone": {
                          "type": "string"
                        },
                        "embedding_attempts": {
                          "type": "number"
                        },
                        "bio": {},
                        "language": {
                          "type": "string"
                        },
                        "live_gmv_30d": {
                          "type": "number"
                        },
                        "pps": {},
                        "msg_name": {
                          "type": "string"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "creator_id": "7171717171717171717",
                        "category": [
                          "Menswear & Underwear",
                          "Phones & Electronics",
                          "Beauty & Personal Care"
                        ],
                        "top_follower_ages": [
                          "18-24",
                          "25-34"
                        ],
                        "handle": "thysamus",
                        "nickname": "sam",
                        "email": null,
                        "follower_cnt": 16983,
                        "is_fast_growing": false,
                        "med_gmv_revenue_range": 1,
                        "units_sold_range": 1,
                        "top_follower_gender": "Female",
                        "video_avg_view_cnt": 0,
                        "video_engagement": 0,
                        "spanish": false,
                        "post_rate": 33.02,
                        "gender": "male",
                        "med_gmv_revenue": 0,
                        "brand_collaborations": 0,
                        "gmv_range": 0,
                        "race": "none",
                        "body_type": "average",
                        "economic_status": "none",
                        "age": "teen",
                        "face_visibility": "frequently",
                        "tone": "humorous",
                        "embedding_attempts": 2,
                        "bio": null,
                        "language": "english",
                        "live_gmv_30d": 0,
                        "pps": null,
                        "msg_name": "Sam"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/creators/brands/list": {
      "post": {
        "operationId": "entCreatorBrands",
        "summary": "Creator's Brands",
        "description": "Given a `creator_id` (from Brand's Creators, Product's Creators, or Creator Performance), retrieve which brands a creator has driven revenue for over a time window.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Creators"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-creator-brands"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/creators/brands/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "creator_id": {
                        "type": "string"
                      },
                      "page_number": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "sort": {
                        "type": "string"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "creator_id": "7493993245181314497",
                  "page_number": 1,
                  "page_size": 10,
                  "sort": "gmv",
                  "ts_start": "2026-03-07",
                  "ts_end": "2026-04-06"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "creator_id": {
                          "type": "string"
                        },
                        "region": {
                          "type": "string"
                        },
                        "ts_start": {
                          "type": "string",
                          "format": "date"
                        },
                        "ts_end": {
                          "type": "string",
                          "format": "date"
                        },
                        "page_number": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "gmv": {
                                "type": "number"
                              },
                              "views": {
                                "type": "number"
                              },
                              "videos": {
                                "type": "number"
                              },
                              "brand_name": {
                                "type": "string"
                              },
                              "brand_id": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "creator_id": "7493993245181314497",
                        "region": "us",
                        "ts_start": "2026-03-07",
                        "ts_end": "2026-04-06",
                        "page_number": 1,
                        "page_size": 10,
                        "has_more": true,
                        "results": [
                          {
                            "gmv": 24595.22,
                            "views": 1600249.31,
                            "videos": 4,
                            "brand_name": "Color Wow UK",
                            "brand_id": "7494530868351044030"
                          },
                          {
                            "gmv": 20236.33,
                            "views": 1347692.71,
                            "videos": 2,
                            "brand_name": "DR.DENT - shop",
                            "brand_id": "7495899075622504605"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/creators/products/list": {
      "post": {
        "operationId": "entCreatorProducts",
        "summary": "Creator's Products",
        "description": "Given a `creator_id`, retrieve which products a creator has driven revenue for over a time window. Returns product-level GMV, views, video count, price, and associated brand.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Creators"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-creator-products"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/creators/products/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "creator_id": {
                        "type": "string"
                      },
                      "page_number": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "sort": {
                        "type": "string"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "creator_id": "7493993245181314497",
                  "page_number": 1,
                  "page_size": 10,
                  "sort": "gmv",
                  "ts_start": "2026-03-07",
                  "ts_end": "2026-04-06"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "creator_id": {
                          "type": "string"
                        },
                        "region": {
                          "type": "string"
                        },
                        "ts_start": {
                          "type": "string",
                          "format": "date"
                        },
                        "ts_end": {
                          "type": "string",
                          "format": "date"
                        },
                        "page_number": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "product_id": {
                                "type": "string"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "views": {
                                "type": "number"
                              },
                              "videos": {
                                "type": "number"
                              },
                              "product_name": {
                                "type": "string"
                              },
                              "price_value": {
                                "type": "number"
                              },
                              "brand_id": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "creator_id": "7493993245181314497",
                        "region": "us",
                        "ts_start": "2026-03-07",
                        "ts_end": "2026-04-06",
                        "page_number": 1,
                        "page_size": 10,
                        "has_more": false,
                        "results": [
                          {
                            "product_id": "1729635919293618333",
                            "gmv": 20236.33,
                            "views": 1347692.71,
                            "videos": 2,
                            "product_name": "DRDENT Purple Teeth Whitening Strips",
                            "price_value": 13.71,
                            "brand_id": "7495899075622504605"
                          },
                          {
                            "product_id": "1729734771029678669",
                            "gmv": 17712.33,
                            "views": 1189024.33,
                            "videos": 3,
                            "product_name": "Soft Glam Satin Concealer",
                            "price_value": 6,
                            "brand_id": "7495889862678710861"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/creators/videos/list": {
      "post": {
        "operationId": "entCreatorVideos",
        "summary": "Creator's Videos",
        "description": "Given a `creator_id`, list videos posted by that creator over a time window. Optionally restrict to a specific brand and/or product the creator featured.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Creators"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-creator-videos"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/creators/videos/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Body accepts either the **nested** form shown above or a **flat** form where the params sit at the top level alongside `region`. If `region` is set inside `params`, it overrides the top-level value.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "creator_id": {
                        "type": "string"
                      },
                      "brand_id": {
                        "type": "string"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "sort": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "is_ad": {
                        "type": "boolean"
                      },
                      "is_ai": {
                        "type": "boolean"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  },
                  "creator_id": {
                    "type": "string",
                    "description": "**Required.** The creator to slice by. `creator_oecuid` and `author_id` are accepted as aliases."
                  },
                  "brand_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict to videos for this brand. `shop_id` is accepted as an alias."
                  },
                  "product_id": {
                    "type": "string",
                    "description": "*(optional)* Restrict to videos featuring this product."
                  },
                  "page": {
                    "type": "integer",
                    "description": "Page number, ≥ 1. Defaults to `1`. `page_number` is accepted as an alias."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Results per page. Defaults to `10`, max `100`."
                  },
                  "sort": {
                    "type": "string",
                    "enum": [
                      "time_posted",
                      "views",
                      "likes",
                      "comments",
                      "gmv"
                    ],
                    "description": "One of `time_posted`, `views`, `likes`, `comments`, `gmv`. Defaults to `gmv`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "asc",
                      "desc"
                    ],
                    "description": "`asc` or `desc`. Defaults to `desc`."
                  },
                  "is_ad": {
                    "type": "boolean",
                    "description": "*(optional)* Filter to videos where `is_ad = true/false`. Unset returns both."
                  },
                  "is_ai": {
                    "type": "boolean",
                    "description": "*(optional)* Filter to videos where `is_ai = true/false`. Unset returns both."
                  },
                  "ts_start": {
                    "type": "string",
                    "format": "date",
                    "description": "*(optional)* `YYYY-MM-DD` lower bound on `time_posted`."
                  },
                  "ts_end": {
                    "type": "string",
                    "format": "date",
                    "description": "*(optional)* `YYYY-MM-DD` upper bound on `time_posted`."
                  },
                  "ts_days": {
                    "type": "integer",
                    "description": "*(optional)* If only one of `ts_start`/`ts_end` is provided, widens the missing side by this many days. Defaults to `7`. Only applied when at least one of `ts_start`/`ts_end` is set."
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "creator_id": "7494011944972290621",
                  "brand_id": "7495957905333913613",
                  "page_size": 10,
                  "sort": "time_posted",
                  "sort_direction": "desc",
                  "is_ad": false,
                  "is_ai": false,
                  "ts_start": "2026-01-01",
                  "ts_end": "2026-05-21"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "video_id": {
                                "type": "string"
                              },
                              "video_link": {
                                "type": "string"
                              },
                              "creator_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "brand_id": {
                                "type": "string"
                              },
                              "product_id": {
                                "type": "string"
                              },
                              "description": {
                                "type": "string"
                              },
                              "time_posted": {
                                "type": "string"
                              },
                              "is_ad": {
                                "type": "number"
                              },
                              "is_ai": {
                                "type": "number"
                              },
                              "views": {
                                "type": "number"
                              },
                              "likes": {
                                "type": "number"
                              },
                              "comments": {
                                "type": "number"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "categories": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "language": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "page": 1,
                        "page_size": 10,
                        "has_more": true,
                        "results": [
                          {
                            "video_id": "7628815395075509517",
                            "video_link": "https://tiktok.com/@dealsbyaxel/video/7628815395075509517",
                            "creator_id": "7494011944972290621",
                            "handle": "dealsbyaxel",
                            "brand_id": "7495957905333913613",
                            "product_id": "1732273880228925453",
                            "description": "Mantente fresco este verano #summerheat #towerfan ...",
                            "time_posted": "2026-04-15T03:00:12",
                            "is_ad": 0,
                            "is_ai": 0,
                            "views": 949400,
                            "likes": 4977,
                            "comments": 87,
                            "gmv": 8399.58,
                            "categories": [
                              "Household Appliances",
                              "Home Appliances"
                            ],
                            "language": "es"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/brands/search": {
      "post": {
        "operationId": "entBrandSearch",
        "summary": "Brand Search",
        "description": "Search for brands across TikTok Shop by name. Returns brand performance metrics over a time window including GMV, views, creator count, and top category. Supports regional filtering.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Brands"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-brand-search"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/brands/search"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "page_number": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "search": {
                        "type": "string"
                      },
                      "category": {},
                      "sort": {
                        "type": "string"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "page_number": 1,
                  "page_size": 10,
                  "search": "Shark",
                  "category": null,
                  "sort": "gmv",
                  "ts_start": "2026-03-07",
                  "ts_end": "2026-04-06"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "brand_id": {
                            "type": "string"
                          },
                          "brand_name": {
                            "type": "string"
                          },
                          "creator_count": {
                            "type": "integer"
                          },
                          "top_category": {
                            "type": "string"
                          },
                          "region": {
                            "type": "string"
                          },
                          "gmv": {
                            "type": "number"
                          },
                          "views": {
                            "type": "number"
                          },
                          "video_count": {
                            "type": "integer"
                          },
                          "shop_name": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "brand_id": "7496047005540322107",
                          "brand_name": "Shark",
                          "creator_count": 4737,
                          "top_category": "Household Appliances",
                          "region": "us",
                          "gmv": 3026883.79,
                          "views": 149453235.52,
                          "video_count": 12789,
                          "shop_name": "Shark UK"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/brands/creators/list": {
      "post": {
        "operationId": "entBrandCreators",
        "summary": "Brand's Creators",
        "description": "Given a `brand_id` (from Brand Search), retrieve the creators driving revenue for that brand over a time window. Returns full creator profiles including demographics, category splits, follower breakdowns, and brand-specific GMV.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Brands"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-brand-creators"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/brands/creators/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "brand_id": {
                        "type": "string"
                      },
                      "page_number": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "sort": {
                        "type": "string"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "brand_id": "7495899075622504605",
                  "page_number": 1,
                  "page_size": 10,
                  "sort": "gmv",
                  "ts_start": "2026-03-07",
                  "ts_end": "2026-04-06"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "handle": {
                                "type": "string"
                              },
                              "nickname": {
                                "type": "string"
                              },
                              "bio": {
                                "type": "string"
                              },
                              "follower_cnt": {
                                "type": "integer"
                              },
                              "category": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "top_follower_ages": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "top_follower_gender": {
                                "type": "string"
                              },
                              "video_avg_view_cnt": {
                                "type": "integer"
                              },
                              "video_engagement": {
                                "type": "number"
                              },
                              "brand_collaborations": {
                                "type": "number"
                              },
                              "med_gmv_revenue": {
                                "type": "number",
                                "description": "total GMV earned across the platform in the last 30 days"
                              },
                              "category_splits": {
                                "type": "object",
                                "properties": {
                                  "Beauty & Personal Care": {
                                    "type": "number"
                                  },
                                  "Health": {
                                    "type": "number"
                                  }
                                }
                              },
                              "follower_gender_breakdown": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "key": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "follower_age_breakdown": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "key": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "regional_geography": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "key": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "email": {
                                "type": "string"
                              },
                              "gender": {
                                "type": "string"
                              },
                              "age": {
                                "type": "string"
                              },
                              "language": {
                                "type": "string"
                              },
                              "shop_gmv": {
                                "type": "number"
                              },
                              "video_count": {
                                "type": "integer"
                              },
                              "creator_id": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "handle": "example_creator",
                            "nickname": "Example Creator",
                            "bio": "Beauty & lifestyle creator",
                            "follower_cnt": 103155,
                            "category": [
                              "Beauty & Personal Care",
                              "Health"
                            ],
                            "top_follower_ages": [
                              "25-34",
                              "35-44"
                            ],
                            "top_follower_gender": "Female",
                            "video_avg_view_cnt": 695,
                            "video_engagement": 170,
                            "brand_collaborations": 80,
                            "med_gmv_revenue": 142337,
                            "category_splits": {
                              "Beauty & Personal Care": 68.88,
                              "Health": 17.07
                            },
                            "follower_gender_breakdown": [
                              {
                                "key": "male",
                                "value": 0.3768
                              },
                              {
                                "key": "female",
                                "value": 0.4879
                              }
                            ],
                            "follower_age_breakdown": [
                              {
                                "key": "25-34",
                                "value": 0.304
                              },
                              {
                                "key": "35-44",
                                "value": 0.2674
                              },
                              {
                                "key": "18-24",
                                "value": 0.182
                              }
                            ],
                            "regional_geography": [
                              {
                                "key": "ENGLAND",
                                "value": 7106
                              },
                              {
                                "key": "SCOTLAND",
                                "value": 762
                              }
                            ],
                            "email": "creator@example.com",
                            "gender": "female",
                            "age": "20s",
                            "language": "english",
                            "shop_gmv": 33893.1,
                            "video_count": 30,
                            "creator_id": "7494974553083775074"
                          }
                        ],
                        "has_more": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/brands/videos/list": {
      "post": {
        "operationId": "entBrandVideos",
        "summary": "Brand's Videos",
        "description": "Given a `brand_id` (from Brand Search), list videos posted about products belonging to that brand over a time window. Returns per-video performance (views, likes, comments, GMV), the creator who posted it, the product featured, and content metadata (categories, language, ad/AI flags).\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Brands"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-brand-videos"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/brands/videos/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Body accepts either the **nested** form shown above or a **flat** form where the params sit at the top level alongside `region` (e.g. `{ \"region\": \"us\", \"brand_id\": \"...\", \"sort\": \"gmv\" }`). If `region` is set inside `params`, it overrides the top-level value.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "brand_id": {
                        "type": "string"
                      },
                      "page": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "sort": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "is_ad": {
                        "type": "boolean"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  },
                  "brand_id": {
                    "type": "string",
                    "description": "**Required.** The brand to slice by. `shop_id` is accepted as an alias."
                  },
                  "page": {
                    "type": "integer",
                    "description": "Page number, ≥ 1. Defaults to `1`. `page_number` is accepted as an alias."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Results per page. Defaults to `10`, max `100`."
                  },
                  "sort": {
                    "type": "string",
                    "enum": [
                      "time_posted",
                      "views",
                      "likes",
                      "comments",
                      "gmv"
                    ],
                    "description": "One of `time_posted`, `views`, `likes`, `comments`, `gmv`. Defaults to `gmv`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "asc",
                      "desc"
                    ],
                    "description": "`asc` or `desc`. Defaults to `desc`."
                  },
                  "is_ad": {
                    "type": "boolean",
                    "description": "*(optional)* Filter to videos where `is_ad = true/false`. Unset returns both."
                  },
                  "is_ai": {
                    "type": "boolean",
                    "description": "*(optional)* Filter to videos where `is_ai = true/false`. Unset returns both."
                  },
                  "ts_start": {
                    "type": "string",
                    "format": "date",
                    "description": "*(optional)* `YYYY-MM-DD` lower bound on `time_posted`."
                  },
                  "ts_end": {
                    "type": "string",
                    "format": "date",
                    "description": "*(optional)* `YYYY-MM-DD` upper bound on `time_posted`."
                  },
                  "ts_days": {
                    "type": "integer",
                    "description": "*(optional)* If only one of `ts_start`/`ts_end` is provided, widens the missing side by this many days. Defaults to `7`. Only applied when at least one of `ts_start`/`ts_end` is set."
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "brand_id": "7495514739648989419",
                  "page": 1,
                  "page_size": 10,
                  "sort": "gmv",
                  "sort_direction": "desc",
                  "is_ad": true,
                  "ts_start": "2026-01-01",
                  "ts_end": "2026-05-21"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "video_id": {
                                "type": "string"
                              },
                              "video_link": {
                                "type": "string"
                              },
                              "creator_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "brand_id": {
                                "type": "string"
                              },
                              "product_id": {
                                "type": "string"
                              },
                              "description": {
                                "type": "string"
                              },
                              "time_posted": {
                                "type": "string"
                              },
                              "is_ad": {
                                "type": "number"
                              },
                              "is_ai": {
                                "type": "number"
                              },
                              "views": {
                                "type": "number"
                              },
                              "likes": {
                                "type": "number"
                              },
                              "comments": {
                                "type": "number"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "categories": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "language": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "page": 1,
                        "page_size": 10,
                        "has_more": true,
                        "results": [
                          {
                            "video_id": "7628775782449433870",
                            "video_link": "https://tiktok.com/@thestephedition/video/7628775782449433870",
                            "creator_id": "7494010987393321524",
                            "handle": "thestephedition",
                            "brand_id": "7495514739648989419",
                            "product_id": "1729508370969629931",
                            "description": "Korean labs are flexin' with the stick version  #medicube #volufiline #pdrn ",
                            "time_posted": "2026-04-15T00:26:26",
                            "is_ad": 1,
                            "is_ai": 0,
                            "views": 18700000,
                            "likes": 110000,
                            "comments": 142,
                            "gmv": 18942,
                            "categories": [
                              "Beauty & Personal Care",
                              "Skincare"
                            ],
                            "language": "en"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/products/search": {
      "post": {
        "operationId": "entProductSearch",
        "summary": "Product Search",
        "description": "Search for products across TikTok Shop by name. Returns product performance metrics over a time window including GMV, units sold, views, creator count, and associated brand.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Products"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-product-search"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/products/search"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "page_number": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "search": {
                        "type": "string"
                      },
                      "category": {},
                      "sort": {
                        "type": "string"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "page_number": 1,
                  "page_size": 10,
                  "search": "Whitening Strips",
                  "category": null,
                  "sort": "gmv",
                  "ts_start": "2026-03-07",
                  "ts_end": "2026-04-06"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "product_id": {
                            "type": "string"
                          },
                          "product_name": {
                            "type": "string"
                          },
                          "price_value": {
                            "type": "number"
                          },
                          "creator_count": {
                            "type": "integer"
                          },
                          "shop_name": {
                            "type": "string"
                          },
                          "gmv": {
                            "type": "number"
                          },
                          "units_sold": {
                            "type": "number"
                          },
                          "views": {
                            "type": "number"
                          },
                          "video_count": {
                            "type": "integer"
                          },
                          "brand_id": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": [
                        {
                          "product_id": "1729635919293618333",
                          "product_name": "DRDENT Purple Teeth Whitening Strips",
                          "price_value": 13.71,
                          "creator_count": 3597,
                          "shop_name": "DR.DENT - shop",
                          "gmv": 400820.59,
                          "units_sold": 29237,
                          "views": 54625344,
                          "video_count": 2704,
                          "brand_id": "7495899075622504605"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/products/creators/list": {
      "post": {
        "operationId": "entProductCreators",
        "summary": "Product's Creators",
        "description": "Given a `product_id` (from Product Search), retrieve the creators driving revenue for that product over a time window. Same response shape as Brand's Creators, with `product_gmv` instead of `shop_gmv`.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Products"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-product-creators"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/products/creators/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "product_id": {
                        "type": "string"
                      },
                      "page_number": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "sort": {
                        "type": "string"
                      },
                      "ts_start": {
                        "type": "string",
                        "format": "date"
                      },
                      "ts_end": {
                        "type": "string",
                        "format": "date"
                      }
                    }
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "product_id": "1729635919293618333",
                  "page_number": 1,
                  "page_size": 10,
                  "sort": "gmv",
                  "ts_start": "2026-03-07",
                  "ts_end": "2026-04-06"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "handle": {
                                "type": "string"
                              },
                              "nickname": {
                                "type": "string"
                              },
                              "bio": {
                                "type": "string"
                              },
                              "follower_cnt": {
                                "type": "integer"
                              },
                              "category": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "top_follower_ages": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "top_follower_gender": {
                                "type": "string"
                              },
                              "video_avg_view_cnt": {
                                "type": "integer"
                              },
                              "video_engagement": {
                                "type": "number"
                              },
                              "brand_collaborations": {
                                "type": "number"
                              },
                              "med_gmv_revenue": {
                                "type": "number",
                                "description": "total GMV earned across the platform in the last 30 days"
                              },
                              "category_splits": {
                                "type": "object",
                                "properties": {
                                  "Beauty & Personal Care": {
                                    "type": "number"
                                  },
                                  "Health": {
                                    "type": "number"
                                  }
                                }
                              },
                              "follower_gender_breakdown": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "key": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "follower_age_breakdown": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "key": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "regional_geography": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "key": {
                                      "type": "string"
                                    },
                                    "value": {
                                      "type": "number"
                                    }
                                  }
                                }
                              },
                              "email": {
                                "type": "string"
                              },
                              "gender": {
                                "type": "string"
                              },
                              "age": {
                                "type": "string"
                              },
                              "language": {
                                "type": "string"
                              },
                              "product_gmv": {
                                "type": "number"
                              },
                              "video_count": {
                                "type": "integer"
                              },
                              "creator_id": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "has_more": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "results": [
                          {
                            "handle": "example_creator",
                            "nickname": "Example Creator",
                            "bio": "Beauty creator",
                            "follower_cnt": 29255,
                            "category": [
                              "Beauty & Personal Care",
                              "Health"
                            ],
                            "top_follower_ages": [
                              "35-44",
                              "25-34"
                            ],
                            "top_follower_gender": "Female",
                            "video_avg_view_cnt": 1114,
                            "video_engagement": 120,
                            "brand_collaborations": 28,
                            "med_gmv_revenue": 88103,
                            "category_splits": {
                              "Beauty & Personal Care": 96.48,
                              "Health": 3
                            },
                            "follower_gender_breakdown": [
                              {
                                "key": "male",
                                "value": 0.1606
                              },
                              {
                                "key": "female",
                                "value": 0.7009
                              }
                            ],
                            "follower_age_breakdown": [
                              {
                                "key": "35-44",
                                "value": 0.3272
                              },
                              {
                                "key": "25-34",
                                "value": 0.2417
                              }
                            ],
                            "regional_geography": [
                              {
                                "key": "ENGLAND",
                                "value": 8189
                              },
                              {
                                "key": "SCOTLAND",
                                "value": 848
                              }
                            ],
                            "email": "creator@example.com",
                            "gender": "female",
                            "age": "30s",
                            "language": "english",
                            "product_gmv": 22143.32,
                            "video_count": 16,
                            "creator_id": "7495894823766755988"
                          }
                        ],
                        "has_more": true
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/intelligence/products/videos/list": {
      "post": {
        "operationId": "entProductVideos",
        "summary": "Product's Videos",
        "description": "Given a `product_id` (from Product Search), list videos that feature that product over a time window. Returns the same per-video performance and metadata as `Brand's Videos`.\n\n**Enterprise tier:** requires an Enterprise API plan; a Standard key receives an authorization error.",
        "tags": [
          "Products"
        ],
        "externalDocs": {
          "url": "https://cruva.com/docs/api#ent-product-videos"
        },
        "security": [
          {
            "apiKey": [
              "POST /intelligence/products/videos/list"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ShopId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Body accepts either the **nested** form shown above or a **flat** form where the params sit at the top level alongside `region`. If `region` is set inside `params`, it overrides the top-level value.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "region": {
                    "type": "string",
                    "description": "us | uk | mx | es | de | ie | it | fr | nl | pt | gr | be | at | pl | hu | cz | br | jp"
                  },
                  "params": {
                    "type": "object",
                    "properties": {
                      "product_id": {
                        "type": "string"
                      },
                      "page": {
                        "type": "integer"
                      },
                      "page_size": {
                        "type": "integer"
                      },
                      "sort": {
                        "type": "string"
                      },
                      "sort_direction": {
                        "type": "string"
                      },
                      "is_ai": {
                        "type": "boolean"
                      }
                    }
                  },
                  "product_id": {
                    "type": "string",
                    "description": "**Required.** The product to slice by."
                  },
                  "page": {
                    "type": "integer",
                    "description": "Page number, ≥ 1. Defaults to `1`. `page_number` is accepted as an alias."
                  },
                  "page_size": {
                    "type": "integer",
                    "description": "Results per page. Defaults to `10`, max `100`."
                  },
                  "sort": {
                    "type": "string",
                    "enum": [
                      "time_posted",
                      "views",
                      "likes",
                      "comments",
                      "gmv"
                    ],
                    "description": "One of `time_posted`, `views`, `likes`, `comments`, `gmv`. Defaults to `gmv`."
                  },
                  "sort_direction": {
                    "type": "string",
                    "enum": [
                      "asc",
                      "desc"
                    ],
                    "description": "`asc` or `desc`. Defaults to `desc`."
                  },
                  "is_ad": {
                    "type": "boolean",
                    "description": "*(optional)* Filter to videos where `is_ad = true/false`. Unset returns both."
                  },
                  "is_ai": {
                    "type": "boolean",
                    "description": "*(optional)* Filter to videos where `is_ai = true/false`. Unset returns both."
                  },
                  "ts_start": {
                    "type": "string",
                    "format": "date",
                    "description": "*(optional)* `YYYY-MM-DD` lower bound on `time_posted`."
                  },
                  "ts_end": {
                    "type": "string",
                    "format": "date",
                    "description": "*(optional)* `YYYY-MM-DD` upper bound on `time_posted`."
                  },
                  "ts_days": {
                    "type": "integer",
                    "description": "*(optional)* If only one of `ts_start`/`ts_end` is provided, widens the missing side by this many days. Defaults to `7`. Only applied when at least one of `ts_start`/`ts_end` is set."
                  }
                }
              },
              "example": {
                "region": "us",
                "params": {
                  "product_id": "1729508370969629931",
                  "page": 1,
                  "page_size": 10,
                  "sort": "views",
                  "sort_direction": "desc",
                  "is_ai": false
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "page": {
                          "type": "integer"
                        },
                        "page_size": {
                          "type": "integer"
                        },
                        "has_more": {
                          "type": "boolean"
                        },
                        "results": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "video_id": {
                                "type": "string"
                              },
                              "video_link": {
                                "type": "string"
                              },
                              "creator_id": {
                                "type": "string"
                              },
                              "handle": {
                                "type": "string"
                              },
                              "brand_id": {
                                "type": "string"
                              },
                              "product_id": {
                                "type": "string"
                              },
                              "description": {
                                "type": "string"
                              },
                              "time_posted": {
                                "type": "string"
                              },
                              "is_ad": {
                                "type": "number"
                              },
                              "is_ai": {
                                "type": "number"
                              },
                              "views": {
                                "type": "number"
                              },
                              "likes": {
                                "type": "number"
                              },
                              "comments": {
                                "type": "number"
                              },
                              "gmv": {
                                "type": "number"
                              },
                              "categories": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "language": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "default": {
                    "summary": "Example response",
                    "value": {
                      "data": {
                        "page": 1,
                        "page_size": 10,
                        "has_more": true,
                        "results": [
                          {
                            "video_id": "7631027139160067342",
                            "video_link": "https://tiktok.com/@thefaceglow/video/7631027139160067342",
                            "creator_id": "7496236347295828872",
                            "handle": "thefaceglow",
                            "brand_id": "7495514739648989419",
                            "product_id": "1729508370969629931",
                            "description": "After 30 we need powerful active ingredients...",
                            "time_posted": "2026-04-21T02:03:04",
                            "is_ad": 1,
                            "is_ai": 0,
                            "views": 9200000,
                            "likes": 59600,
                            "comments": 1102,
                            "gmv": 11256,
                            "categories": [
                              "Beauty & Personal Care",
                              "Skincare"
                            ],
                            "language": "en"
                          }
                        ]
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        },
        "x-cruva-tier": "enterprise"
      }
    },
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Liveness check for api.cruva.com. Needs no API key; returns `{\"status\": \"ok\"}` when the API is up.",
        "tags": [
          "Status"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The API is up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok"
                      ]
                    }
                  },
                  "required": [
                    "status"
                  ]
                },
                "example": {
                  "status": "ok"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Cruva API key (`cruva_…`), created in the dashboard at /dashboard/api. A key may be limited to a subset of routes (the permissions in `x-scopes`, named in each operation's security requirement) and to a subset of shops.",
        "x-scopes": {
          "GET /idempotency/<key>": "Idempotency: Lookup by Key",
          "GET /account/shops": "Account: List Shops",
          "POST /shop/products": "Products: List Shop Products",
          "POST /shop/skus": "Products: List Shop SKUs",
          "POST /timeseries/products": "Products: Product Timeseries Search",
          "POST /timeseries/skus": "Products: SKU Timeseries Search",
          "POST /shop/stats": "Analytics: Shop Stats",
          "GET /shop/sps": "Shop health: Shop Performance Score",
          "POST /halo-effect": "Halo Effect: Report",
          "POST /halo-effect/product-links": "Halo Effect: Product Links",
          "POST /affiliate/crm/list": "CRM & Content: CRM Search",
          "POST /affiliate/videos/list": "CRM & Content: Videos Search",
          "POST /timeseries/affiliates": "CRM & Content: CRM Timeseries Search",
          "POST /timeseries/videos": "CRM & Content: Video Timeseries Search",
          "POST /affiliate/slideshows/list": "CRM & Content: Carousel Search",
          "POST /timeseries/slideshows": "CRM & Content: Carousel Timeseries Search",
          "POST /affiliate/lives/list": "CRM & Content: LIVE Stream Search",
          "POST /spark/list": "TikTok Ads: Spark Ad Search",
          "POST /ads/campaigns": "TikTok Ads: List Campaigns",
          "POST /ads/creatives": "TikTok Ads: List Creatives",
          "POST /ads/excluded-creatives": "TikTok Ads: List Excluded Creatives",
          "POST /ads/boosted-creatives": "TikTok Ads: List Boosted Creatives",
          "POST /meta/campaigns": "Meta Ads: List Campaigns",
          "POST /meta/adsets": "Meta Ads: List Ad Sets",
          "POST /meta/ads": "Meta Ads: List Ads",
          "POST /meta/programs": "Meta Ads: List Programs",
          "POST /meta/programs/creators": "Meta Ads: List Program Creators",
          "POST /affiliate/samples/funnel": "Sample Requests: Sample Funnel",
          "POST /affiliate/samples/list": "Sample Requests: Sample Request Search",
          "POST /affiliate/samples/refundable/list": "Sample Requests: Refundable Sample Request Search",
          "POST /affiliate/samples/approve": "Sample Requests: Approve Sample Requests",
          "POST /affiliate/samples/reject": "Sample Requests: Reject Sample Requests",
          "POST /affiliate/samples/ignore": "Sample Requests: Ignore Sample Requests",
          "POST /affiliate/samples/unignore": "Sample Requests: Unignore Sample Requests",
          "POST /affiliate/message/dm": "Outreach: Send Direct Message",
          "POST /affiliate/message/list": "Outreach: List Messages",
          "POST /affiliate/message/inbox": "Outreach: List Inbox",
          "POST /outreach/logs/list": "Outreach: List Activity Logs",
          "POST /automations/list": "Automations: List Automations",
          "POST /automations/create": "Automations: Create Automation",
          "GET /emails/senders/list": "Email Campaigns: List Sender Emails",
          "POST /emails/senders/create-custom": "Email Campaigns: Create Custom Sender Email",
          "POST /emails/senders/update-sender-name": "Email Campaigns: Update Sender Name",
          "POST /emails/campaigns/create": "Email Campaigns: Create Email Campaign",
          "POST /emails/campaigns/list": "Email Campaigns: List Email Campaigns",
          "POST /emails/campaigns/update": "Email Campaigns: Update Email Campaign",
          "POST /emails/campaigns/toggle": "Email Campaigns: Start / Stop",
          "DELETE /emails/campaigns/delete": "Email Campaigns: Delete Email Campaign",
          "POST /automations/update": "Automations: Update Automation",
          "POST /automations/toggle": "Automations: Toggle Automation",
          "DELETE /automations/delete": "Automations: Delete Automation",
          "GET /automations/categories/list": "Automations: List Categories",
          "POST /groups/list": "Groups: List Groups",
          "POST /groups/create": "Groups: Create Group",
          "DELETE /groups/delete": "Groups: Delete Group",
          "POST /lists/create": "Lists: Create List",
          "POST /lists/list": "Lists: List Lists",
          "POST /lists/get": "Lists: Get List Members",
          "POST /lists/rename": "Lists: Rename List",
          "POST /lists/merge": "Lists: Merge Lists",
          "POST /lists/remove": "Lists: Remove Entries",
          "DELETE /lists/delete": "Lists: Delete List",
          "POST /tags/list": "Tags: List Tags",
          "POST /tags/add": "Tags: Tag Creators",
          "POST /tags/remove": "Tags: Remove Tags",
          "POST /workflows/list": "Workflows: List Workflows",
          "POST /workflows/get": "Workflows: Get Workflow",
          "POST /workflows/campaigns": "Workflows: List Campaigns",
          "POST /workflows/create": "Workflows: Create Workflow",
          "POST /workflows/toggle": "Workflows: Activate / Pause",
          "DELETE /workflows/delete": "Workflows: Delete Workflow",
          "POST /creator-briefs/create": "Creator Briefs: Create Brief",
          "POST /creator-briefs/update": "Creator Briefs: Update Brief",
          "POST /creator-briefs/list": "Creator Briefs: List Briefs",
          "DELETE /creator-briefs/delete": "Creator Briefs: Delete Brief",
          "POST /community/campaigns/list": "Community: List Campaigns",
          "POST /community/campaigns/get": "Community: Get Campaign",
          "POST /community/campaigns/create": "Community: Create Campaign",
          "POST /community/campaigns/update": "Community: Update Campaign",
          "POST /community/campaigns/set_status": "Community: Set Campaign Status",
          "DELETE /community/campaigns/delete": "Community: Delete Campaign",
          "POST /community/campaigns/participants": "Community: List Participants",
          "POST /community/campaigns/participants/set_status": "Community: Approve / Reject Participant",
          "POST /community/campaigns/videos": "Community: List Campaign Videos",
          "POST /community/campaigns/lives": "Community: List Campaign LIVEs",
          "POST /community/discord/members": "Community: Discord Members",
          "POST /community/stats": "Community: Stats",
          "POST /community/balance": "Community: Balance",
          "POST /community/payouts/authorize": "Community: Authorize Payout",
          "POST /community/payouts/manual": "Community: Record Manual Payout",
          "POST /affiliate/marketplace/search": "Creators: Creator Data (Enterprise tier)",
          "POST /intelligence/creators/brands/list": "Creators: Creator's Brands (Enterprise tier)",
          "POST /intelligence/creators/products/list": "Creators: Creator's Products (Enterprise tier)",
          "POST /intelligence/creators/videos/list": "Creators: Creator's Videos (Enterprise tier)",
          "POST /intelligence/brands/search": "Brands: Brand Search (Enterprise tier)",
          "POST /intelligence/brands/creators/list": "Brands: Brand's Creators (Enterprise tier)",
          "POST /intelligence/brands/videos/list": "Brands: Brand's Videos (Enterprise tier)",
          "POST /intelligence/products/search": "Products: Product Search (Enterprise tier)",
          "POST /intelligence/products/creators/list": "Products: Product's Creators (Enterprise tier)",
          "POST /intelligence/products/videos/list": "Products: Product's Videos (Enterprise tier)"
        }
      }
    },
    "parameters": {
      "ShopId": {
        "name": "x-shop-id",
        "in": "header",
        "required": true,
        "description": "The x-shop-id header is a Cruva internal shop ID — it is not the same as your TikTok shop ID/code. To find it: (1) go to cruva.com/dashboard/my-shops, (2) click the dropdown on the right of the shop and choose View Info, (3) copy the Shop ID from the popup. Use List Shops (`GET /account/shops`) to get the IDs your key can use.",
        "schema": {
          "type": "string"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Optional. Replays of the same key within 24 hours return the original response byte-for-byte instead of repeating the write; a concurrent duplicate gets `409`.",
        "schema": {
          "type": "string",
          "pattern": "^[A-Za-z0-9-]{1,128}$"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message."
          }
        },
        "required": [
          "error"
        ],
        "additionalProperties": true
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request body or parameters are invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Missing or invalid API key, a route or shop outside the key's permissions, or an Enterprise endpoint called without an Enterprise plan.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Unauthorized: missing API key"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Back off briefly and retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  }
}