---
title: "Which seller-funded promotions earn"
method: GET
path: "/promotions/performance"
tags: ["Promotions"]
---

# Which seller-funded promotions earn

`GET /promotions/performance`

## Request

- Base URL: `https://api.reacherapp.com/public/v1`
- URL: `https://api.reacherapp.com/public/v1/promotions/performance`
- Auth: API key in header `x-api-key` and API key in header `x-shop-id`

Every seller-funded promotion that touched an order created in the window, one row per promotion and kind, product rows first and then shipping rows, each ranked by line_gmv: orders, units (gift lines excluded), the GMV of the lines that carried it, the mean whole-order GMV of those orders against the same kind's no-promotion baseline, the seller discount it cost and GMV per discount dollar, orders it shared with another promotion of the same kind, and refunded orders. product and shipping promotions are separate rows and must never be summed or ranked together. low_sample marks rows under 20 orders. Numbers cover settled orders only, about a week behind: compare only days before coverage.incomplete_after. A shop the daily price-breakdown sync does not cover reads coverage.state=not_collected with empty rows. Rows total the whole window, so to rank on complete days only, call again with end_date the day before coverage.incomplete_after. Titles, types and windows come from TikTok for the top 20 by line_gmv, cached up to an hour; metadata_status says whether they came back.

## Query parameters

- `start_date` string, date, nullable: Inclusive order-create date (UTC). Defaults to 29 days before end_date.
- `end_date` string, date, nullable: Inclusive order-create date (UTC). Defaults to yesterday.

## Response `200`

Successful Response

- PromotionPerformanceResponse: Seller-funded promotions ranked by the GMV of the lines that carried them, for one shop and window.
  - `shop_id` integer, required
  - `tts_shop_id` string, required
  - `start_date` string, required: Inclusive order-create date (UTC).
  - `end_date` string, required: Inclusive order-create date (UTC).
  - `data` PromotionPerformanceRow[], required: Product rows, then shipping rows, each ranked by line_gmv. Never add a product row to a shipping row.
    - `activity_id` string, required: TikTok activity id, as Seller Center and the Promotion API name it.
    - `promotion_kind` 'product' | 'shipping', required: product: price discounts on items; shipping: shipping-fee discounts. Rank and compare within one kind only.
    - `orders` integer, required: Distinct orders with at least one line carrying this promotion.
    - `units` integer, required: Lines carrying it, gift lines excluded; TikTok sends one line per unit.
    - `line_gmv` number, required: Sum over those lines of sku_list_price minus the seller's product discount. Not the whole orders' GMV.
    - `order_aov` number, nullable: Mean whole-order GMV of the orders it touched.
    - `aov_vs_baseline` number, nullable: order_aov divided by the same kind's baseline order_aov; null when that baseline has no orders.
    - `seller_discount` number, required: What this promotion cost the seller on those lines.
    - `gmv_per_discount_dollar` number, nullable: line_gmv / seller_discount; null when the discount is zero.
    - `overlap_orders` integer, required: Orders that also carried another seller promotion of the same kind; its credit is shared with that one.
    - `refunded_orders` integer, required: Orders with a refund on a settled finance line. GMV is not netted.
    - `first_order_at` string, nullable: ISO timestamp of the earliest order it touched.
    - `last_order_at` string, nullable: ISO timestamp of the latest order it touched.
    - `low_sample` boolean, required: Fewer than 20 orders: too few to rank on.
    - `title` string, nullable: From TikTok, cached up to an hour; null when the metadata read did not return it.
    - `activity_type` string, nullable: From TikTok, cached up to an hour, e.g. FIXED_PRICE, FLASHSALE, BUY_MORE_SAVE_MORE.
    - `status` string, nullable: From TikTok, cached up to an hour (so it can lag), e.g. ONGOING, EXPIRED.
    - `begin_time` string, nullable: ISO timestamp the promotion starts, from TikTok, cached up to an hour.
    - `end_time` string, nullable: ISO timestamp the promotion ends, from TikTok, cached up to an hour.
  - `baselines` PromotionPerformanceBaselines, required: The no-promotion comparison per kind; null when every order carried a promotion of that kind.
    - `product` PromotionPerformanceBaseline: Orders in the window with no seller promotion of one kind on any line.
      - `orders` integer, required
      - `order_aov` number, required: Mean whole-order GMV of those orders.
    - `shipping` PromotionPerformanceBaseline: Orders in the window with no seller promotion of one kind on any line.
      - `orders` integer, required
      - `order_aov` number, required: Mean whole-order GMV of those orders.
  - `shop_totals` PromotionPerformanceTotals, required: Every fetched order in the window, with or without a promotion.
    - `orders` integer, required
    - `lines` integer, required
    - `units` integer, required: Lines excluding gift lines.
    - `gmv` number, required: Sum of line GMV over every line.
    - `seller_product_discount` number, required
    - `seller_shipping_discount` number, required
    - `gift_lines` integer, required
  - `gift_value` number, required: Original price of the gift lines given away in the window.
  - `coverage` PromotionPerformanceCoverage, required: How much of the window the numbers cover. Read it before comparing anything.
    - `state` 'collected' | 'not_collected', required: not_collected: no order of this shop has ever been fetched, so every number is zero by absence.
    - `settled_orders` integer, required: Distinct orders created in the window that have a settled finance line.
    - `fetched_orders` integer, required: Of those, orders whose price breakdown is stored.
    - `failed_orders` integer, required: Orders TikTok returned no breakdown for; retried up to three times. Orders held back after an outage are not counted here: they are still pending.
    - `incomplete_after` string, nullable: First order-create date (UTC) from which the numbers are incomplete: the first day with fewer than 90% of TikTok's own order count fetched, or with no TikTok count to check against, or the day of the oldest settled order still waiting to be fetched, whichever is earliest. Null when every day in the window passed.
    - `tiktok_orders` integer, required: TikTok's own order count summed over the days it reported in the window.
    - `unverified_days` integer, required: Days in the window with no TikTok order count to check against.
    - `finance_status` FinanceDataStatus, required: Freshness and reachability of this shop's finance statements. ``scope_missing`` means the shop's TikTok grant refused the finance scope on the last sync; the fix is to re-authorize, not to retry.
      - `state` union, required: Latest statements-sync status: never_run | ok | empty | partial | scope_missing | unsupported | failed.
        - 'never_run' | 'ok' | 'empty' | 'partial' | 'scope_missing' | 'unsupported' | 'failed'
        - string
      - `last_synced_at` string, nullable: ISO timestamp of the last completed statements window.
      - `covered_from` string, nullable: ISO timestamp where the unbroken run of synced windows begins; nothing before it is known.
      - `covered_until` string, nullable: ISO timestamp up to which data is known to be complete (exclusive); the end of that same unbroken run.
      - `transactions_backlog` integer: Statements whose line items have not fully landed yet.
  - `metadata_status` 'ok' | 'partial' | 'scope_missing', required: ok: every top promotion's title and window came back; partial: some did not; scope_missing: the shop's TikTok grant lacks seller.promotion.info, so rows carry numbers only.

## Other responses

- `400`: Multi-shop key, or an inverted or oversized window.
- `403`: The shop's TikTok grant lacks `seller.finance.info` (`SCOPE_NOT_GRANTED`).
- `404`: The shop has no TikTok shop ID on file.
- `409`: The shop's TikTok connection is missing or must be re-authorized (`SHOP_NOT_CONNECTED`).
- `422`: Validation Error

## Changes

> 76 revisions in range; 1 not diffed.

- **2026-10-28** `c9a57f9d03c8`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/reacherapp/apis/reacher-data-api/changes/promotions/performance/get.md)

---

[API](https://skmtc.dev/reacherapp/apis/reacher-data-api.md) - [All operations](https://skmtc.dev/reacherapp/apis/reacher-data-api/llms.txt) - [OpenAPI document](https://skmtc.dev/reacherapp/apis/reacher-data-api/revisions/63ce74b30b5a?raw)
