---
title: "Seller Center promotions and vouchers, with start and end times"
method: GET
path: "/shop-promotions"
tags: ["Promotion Snapshots"]
---

# Seller Center promotions and vouchers, with start and end times

`GET /shop-promotions`

## Request

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

Activities (product discounts, flash sales, shipping discounts, buy-more-save-more, gifts) and vouchers that are upcoming, live, or ended in the last 90 days, from the newest stored snapshot of each shop. Live first by soonest end, then upcoming, then most recently ended. Times are UTC with a *_shop_tz twin. coverage says per shop which snapshot answered and whether it is current; not_covered lists what TikTok's API cannot show (bundle deals, creator LIVE flash deals, creator-exclusive prices). With product_id or sku_id, filter_complete is false when a promotion's product list could not be read.

## Query parameters

- `status` string[], nullable: Keep these statuses (repeatable).
- `tool_type` string[], nullable: Keep these promotion tools (repeatable).
- `ending_within_hours` integer, nullable: Upcoming or live promotions whose scheduled end is within this many hours.
- `ended_within_days` integer: Ended or deactivated within this many days.
- `product_id` string, nullable: Promotions that list this product.
- `sku_id` string, nullable: With product_id: promotions of this SKU.
- `q` string, nullable: Title contains, or id.
- `page` integer
- `page_size` integer
- `snapshot` string, nullable: The snapshot token from page 1, to read later pages from the same runs (valid 24 h).

## Response `200`

Successful Response

- PromotionsListResponse
  - `data` PromotionSummary[], required
    - `shop_id` integer, required
    - `promotion_kind` 'activity' | 'coupon', required
    - `promotion_id` string, required
    - `title` string, required
    - `tool_type` 'product_discount' | 'flash_sale' | 'shipping_discount' | 'buy_more_save_more' | 'buy_x_get_y' | 'gift_with_purchase' | 'voucher' | 'unknown', required
    - `tiktok_type` string, required: TikTok's own activity_type, or COUPON.
    - `status` 'upcoming' | 'ongoing' | 'ended' | 'deactivated' | 'unknown', required: As of served_snapshot_at. A promotion whose end_at has passed since then can still read ongoing until the next snapshot; compare end_at with the current time.
    - `tiktok_status` string, required
    - `deal_summary` string, required: One line describing the deal, built from the stored fields.
    - `start_at` string, nullable
    - `start_at_shop_tz` string, nullable
    - `end_at` string, nullable: Scheduled end; an indefinite promotion ends about 100 years out.
    - `end_at_shop_tz` string, nullable
    - `ended_at` string, nullable: When it actually stopped: end_at once expired, the last update when deactivated.
    - `ended_at_shop_tz` string, nullable
    - `is_indefinite` boolean
    - `scope` 'shop_wide' | 'products' | 'unknown', required
    - `product_count` integer, nullable
    - `sku_count` integer, nullable
    - `currency` string, nullable
    - `discount_type` string, nullable
    - `discount_amount` string, nullable
    - `discount_percent` string, nullable
    - `max_discount` string, nullable
    - `min_spend` string, nullable
    - `promo_code` string, nullable
    - `coupon_display_type` string, nullable
    - `claim_start_at` string, nullable
    - `claim_end_at` string, nullable
    - `redemption_start_at` string, nullable
    - `redemption_end_at` string, nullable
    - `claimed_count` integer, nullable
    - `redeemed_count` integer, nullable
    - `detail_status` string, required: ok | carried | not_needed | pending | denied | products_dropped | failed
    - `updated_at` string, nullable
  - `pagination` PublicApiCorePaginationPaginationMeta, required: Pagination metadata returned in responses.
    - `total_count` integer, required
    - `page` integer, required
    - `page_size` integer, required
    - `total_pages` integer, required
  - `coverage` ShopCoverage[], required
    - `shop_id` integer, required
    - `shop_timezone` string, required: IANA zone used for the *_shop_tz fields.
    - `promotions` DatasetCoverage, required: Which stored snapshot answered for one dataset of one shop, and how complete and fresh it is.
      - `state` 'collected' | 'degraded' | 'stale' | 'scope_missing' | 'not_collected', required: collected: a complete snapshot under 13 h old. degraded: served, but details are pending, a history branch is capped, or the newest refresh failed. stale: the newest servable snapshot is over 13 h old, or none is under 14 days (then nothing is served). scope_missing: the shop's grants cannot read this data. not_collected: no snapshot exists for this shop.
      - `reason` string, nullable: Why the state is not collected, e.g. no_grant_with_scope.
      - `run_id` string, nullable: The sync run whose snapshot was served.
      - `served_snapshot_at` string, nullable: When the served snapshot was taken (UTC).
      - `last_success_at` string, nullable: When this dataset last refreshed cleanly (UTC).
      - `history_gaps` string[]: Ended-promotion branches TikTok's 10,000-row depth cap hid, e.g. EXPIRED:FLASHSALE.
      - `unresolved_details` integer: Ongoing product-scoped promotions whose product list could not be read in the served snapshot.
    - `prices` DatasetCoverage, required: Which stored snapshot answered for one dataset of one shop, and how complete and fresh it is.
      - `state` 'collected' | 'degraded' | 'stale' | 'scope_missing' | 'not_collected', required: collected: a complete snapshot under 13 h old. degraded: served, but details are pending, a history branch is capped, or the newest refresh failed. stale: the newest servable snapshot is over 13 h old, or none is under 14 days (then nothing is served). scope_missing: the shop's grants cannot read this data. not_collected: no snapshot exists for this shop.
      - `reason` string, nullable: Why the state is not collected, e.g. no_grant_with_scope.
      - `run_id` string, nullable: The sync run whose snapshot was served.
      - `served_snapshot_at` string, nullable: When the served snapshot was taken (UTC).
      - `last_success_at` string, nullable: When this dataset last refreshed cleanly (UTC).
      - `history_gaps` string[]: Ended-promotion branches TikTok's 10,000-row depth cap hid, e.g. EXPIRED:FLASHSALE.
      - `unresolved_details` integer: Ongoing product-scoped promotions whose product list could not be read in the served snapshot.
    - `last_attempt_at` string, nullable: When the sync last tried this shop (UTC).
    - `last_attempt_outcome` string, nullable
  - `not_covered` NotCovered[], required
    - `kind` string, required
    - `reason` string, required
  - `snapshot` string, required: Echo as ?snapshot= on later pages to read the same runs (valid 24 h).
  - `filter_complete` boolean: False when a product_id/sku_id filter could miss a promotion whose product list is unresolved.
  - `unresolved_promotions` UnresolvedPromotion[]
    - `shop_id` integer, required
    - `promotion_kind` 'activity' | 'coupon', required
    - `promotion_id` string, required
    - `detail_status` string, required

## Other responses

- `422`: Validation Error

## Changes

> 76 revisions in range; 1 not diffed.

- **2026-10-26** `e153bb966d50`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/reacherapp/apis/reacher-data-api/changes/shop-promotions/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)
