Skip to main content
Get Started
MomentIQ

TikTok Shop Promotions API: Activities and Coupons Guide

A working guide to the TikTok Shop Promotions API: activities, activity products, coupon search, and the guardrails that keep automated discounts profitable.

By Alex Elsea 11 min read

Promotions are the highest-leverage and highest-risk surface in TikTok Shop automation. Every other API domain moves information or goods; the promotion domain moves your prices. Automate it well and you run flash sales timed to the minute, keep discounts synchronized across hundreds of SKUs, and never leave a stale promo bleeding margin over a weekend. Automate it carelessly and a bug does not throw an error — it sells your inventory below cost, at volume, while the dashboard looks great. This guide maps the promotion surface — activities, activity products, and coupons — and then spends equal time on the part generic API docs skip: the stacking math, scheduling discipline, and audit trail that keep automated discounts profitable.

Key Takeaways
  • The promotion domain splits into two resource families: activities (shop promotion events with product-level discounts) and coupons — and they run on different API versions, 202309 and 202406.
  • Activity lifecycle is explicit: create, update, add or remove products, and deactivate are separate operations — deactivation is your kill switch, so keep every activity_id your system creates.
  • Margin guardrails must validate the worst-case stack — activity discount plus coupon on the same checkout — against a per-SKU floor price, not each promotion in isolation.
  • Promotion writes deserve a dry-run and approval gate; reads (search, get) can run continuously as your reconciliation layer.
  • Log every automated discount with who approved it, what it changed, and what it cost — the audit trail is what turns promotion automation from a liability into a system you can trust.

Promotion types the API can control

Four glass shutters set to different openings along one lit channel

The promotion domain is one of the twenty domains in the TikTok Shop API surface, and it covers two distinct resource families. The first is activities — shop-side promotion events that apply product-level discounts over a defined time window. Flash-sale-style price cuts, scheduled markdowns, event promos: in API terms these are all activities, each with its own lifecycle of create, update, product management, and deactivation. The second family is coupons — the codes and vouchers buyers redeem at checkout, exposed through their own search and detail endpoints.

Two things are deliberately not here. Ad-side promotion — Spark Ads, paid amplification — lives in a different part of the platform entirely and has nothing to do with this domain. And platform-run campaigns that TikTok itself operates are not something your API client creates; your job there is to know they exist, because they can stack with your own discounts (more on that below).

One structural detail worth internalizing before you write a line of code: the two families run on different API versions. The activities endpoints sit on the 202309 version, while the coupon endpoints sit on 202406. A client that hard-codes one version string across the whole promotion domain will build wrong paths for one family or the other. Pin the version per resource family, and treat versioned paths as facts to confirm against the Partner Center docs rather than patterns to extrapolate. All of this rides on the same signed-request plumbing as every other domain — if you have not built that yet, start with our authentication and request signing guide.

Creating and updating activities

The core write is activity creation: POST /promotion/202309/activities registers a new promotion event with the shop. Its counterpart, PUT /promotion/202309/activities, updates an existing one. Around those two sit the reads: POST /promotion/202309/activities/search to enumerate activities and GET /promotion/202309/activities/{activity_id} to fetch one in detail. Ending a promotion is its own operation — POST /promotion/202309/activities/deactivate — not a field you flip on update, which matters operationally: your kill switch is a dedicated call, and it should be wired into monitoring, not buried in a generic update path.

Three disciplines make activity management boring, which is the goal:

  • Own the activity_id. Store the identifier of every activity your system creates, alongside the intent that created it — which campaign, which approval, which discount plan. An activity you cannot trace to an intent is an activity you cannot safely modify or kill.
  • Search before you create. Run the activities search and check for overlap before registering a new promotion. Duplicate or overlapping activities on the same products are how discounts silently compound; the read costs you nothing and the collision costs real margin.
  • Gate the writes. Creation and update are mutations that change what buyers pay. In our own integration work every promotion mutation goes through a dry-run that renders exactly what would change, and a human approves before the call fires. Reads run freely; writes earn their way to autonomy slowly, and price-changing writes earn it last.

Update deserves particular respect. A promotion update is a statement of intent about a live pricing event — validate the full resulting state against your margin rules, not just the delta, because the fields you did not touch still define what the buyer pays.

Adding and removing activity products

An activity without products discounts nothing. Product membership is managed through its own endpoint pair: PUT /promotion/202309/activities/products to add or update the products (and their discount configuration) on an activity, and DELETE /promotion/202309/activities/products to remove them. The separation from activity create/update is useful: the event and its contents have independent lifecycles, and volume sellers exploit that constantly — one long-running activity whose product list rotates is often cleaner than a stream of new activities.

The robust pattern here is reconciliation, not imperative calls. Maintain your intended state — this activity should contain exactly these SKUs at these discounts — in your own system, then diff it against what the get-activity read returns and issue the add or remove calls that close the gap. Imperative scripts that fire adds and removes without a source of truth drift within days: a retry double-adds, a partial failure leaves the activity half-updated, and nobody can say what the promotion is supposed to contain.

Respect the removal call for what it is. Pulling a product out of a live promotion mid-flight changes its effective price for every buyer currently looking at it — carts, LIVE viewers, buyers returning from an earlier session. Batch product changes to scheduled windows where you can, and when you must remove mid-promotion, log it with the same weight as a price change, because from the buyer's side that is exactly what it is.

Coupons: search, issue, and limits

The coupon family gives you the read side of your voucher inventory: POST /promotion/202406/coupons/search to enumerate coupons and GET /promotion/202406/coupons/{coupon_id} to fetch one in detail. For an automation system, the search endpoint is the workhorse even if you never automate coupon creation at all — it is how your margin guardrails learn what vouchers are live right now, which is the single input most discount-stacking incidents are missing.

On issuance, be conservative. Coupon creation and targeting have historically been operated through Seller Center, and the right division of labor for most teams keeps it there: humans design and issue coupons with the platform's own tooling, and your integration ingests the result through search so every downstream system knows what exists. Confirm the current write surface in the Partner Center docs before assuming more; do not build against endpoint shapes you have not verified.

Limits are where coupon strategy actually lives. Every coupon has boundaries — validity window, redemption constraints, which buyers can claim it — and your system should mirror those boundaries in its own model rather than treating a coupon as a flat percentage. Two coupons with the same face discount can have wildly different margin impact depending on how many redemptions they allow and who can reach them. If you are still deciding what coupons should exist in the first place, that is a strategy question rather than an API one — our coupon and discount strategy frameworks cover the eight structures worth automating around.

Stacking rules and margin guardrails

Stacked glass plates dimming a beam further with each added layer

Here is the failure mode that makes promotion automation genuinely dangerous: discounts stack. An activity cuts a product 15 percent. A live coupon takes another 20 percent at checkout. A platform campaign adds its own incentive on top. Each decision was individually reasonable; the combination sells the order below cost. No API error fires, because nothing went wrong from the platform's perspective — you configured all of it.

The defense is a guardrail layer that every proposed promotion write must pass before it reaches the API:

  • A floor price per SKU. Landed cost plus expected affiliate commission plus fulfillment cost plus your minimum acceptable contribution. This number lives in your system, is reviewed when costs change, and is the line no automated discount may cross. The inputs come straight from the unit-economics work in our pricing strategy guide.
  • Worst-case stack simulation. Validate the proposed activity discount against the floor after applying the deepest live coupon that could reach the same checkout — which is exactly why the coupon search read runs continuously. Checking promotions in isolation is how individually-sane discounts compound into a loss.
  • Hard rejection, not warnings. A proposal that breaches the floor is refused before the API call is built. Warnings get clicked through at 11 p.m. before a launch; a refusal with the arithmetic attached gets fixed.
  • Settlement-side verification. Configured discounts are a plan; the payout is the fact. Reconcile promoted orders against actual settlement amounts so fees and commission land in the margin math too — the Finance API settlement guide covers that read path.

Build the guardrail before the first automated write, not after the first incident. It is a few hundred lines of arithmetic protecting the entire downside of the system.

Scheduling promos around LIVE events

The strongest operational case for the promotion API is LIVE commerce. A flash discount that starts when the host announces it and ends when the segment ends is a timing problem humans reliably fumble — someone forgets to end the promo and the "LIVE-only" price runs all night. Code does not forget.

The pattern we run: stage the activity ahead of the stream with its window matching the planned segment, verify it with the get-activity read during pre-stream checks, and hold the deactivate call as the always-armed kill switch — both for ending the segment cleanly and for stopping a promo that is moving inventory faster than planned. Sequence discounts across the stream rather than opening at your deepest cut, and reconcile afterward: pull the activity's actual window and products, join promoted-order revenue from your order sync, and let each stream's numbers sharpen the next one's discount plan. The on-camera mechanics — urgency framing, announcement cadence, sequencing — are their own craft, covered in our flash sales during LIVEs framework; the API's job is making the prices actually do what the host says they will, to the minute.

Audit trail: log every automated discount

A glass ledger column recording each pulse of light as a fixed bright mark

Every automated system that changes prices needs to answer one question on demand: why is this product selling at this price right now? If the answer requires archaeology, the automation is a liability. The audit trail is what makes it an asset, and it has four layers:

  • Intent. Every write starts as a proposal record — the campaign it serves, the discount plan, the guardrail check it passed, and who approved it. No proposal, no API call.
  • Action. Every request and outcome is logged with the returned identifiers, so each live activity traces back through your own records to an approved intent.
  • Effect. Scheduled reads — activities search, coupon search — snapshot what is actually live, and a daily diff against intended state catches drift: the activity someone edited by hand in Seller Center, the update that half-applied, the promo that should have ended yesterday.
  • Cost. Join promoted orders to their discounts and settlement so every promotion has a realized margin number, not just a GMV number. This is the layer that turns the audit trail from compliance into learning — it is how you find out which discount depths actually pay.

Weight the logging by risk. Deactivations and product removals change live buyer-facing prices mid-flight and deserve the loudest records; reads need only enough logging to debug. When something does go wrong — and at some point a promotion will misfire — the trail is the difference between a five-minute rollback with a known blast radius and a morning of guessing which orders shipped at the wrong price.

Versioned paths, request and body requirements, and scopes should always be confirmed against the official TikTok Shop Partner Center API documentation before an integration ships — the promotion domain in particular spans two API versions, and assumptions travel badly.

If you would rather skip straight to the outcome, our TikTok Shop management team runs promotion operations for brands daily — flash-sale timing, margin-guarded discounting, and the reconciliation loop that keeps it honest. Talk to us about your promotion calendar.

Frequently Asked Questions

What promotion types can the TikTok Shop API actually control?

Two families. Activities are shop-side promotion events — product-level discounts that run over a defined time window — managed through the activities endpoints: create, update, search, get by activity_id, deactivate, and product add/remove. Coupons are a separate resource family with their own endpoints for searching your coupon inventory and fetching a single coupon by coupon_id. Ad-side promotion (Spark Ads, paid boosts) lives outside this domain entirely.

Should promotion automation run without human approval?

Not fully, and you should not want it to be. Reads — searching activities, fetching a coupon — are safe to run continuously. Writes that create or change a discount deserve a proposal-and-approval flow: the system computes the change, checks it against margin floors, and a human approves before anything goes live. The point of automation is to eliminate the spreadsheet work and the timing errors, not the judgment call on giving away margin.

How do I stop automated discounts from stacking into negative margin?

Compute a floor price per SKU from landed cost, expected commission, fulfillment cost, and a minimum acceptable contribution — then validate every proposed activity discount and coupon against the worst-case combination that could apply to one order, not each promotion in isolation. A 15 percent activity discount and a 20 percent coupon that are each fine alone can stack into a loss on the same checkout.

Why do the activity and coupon endpoints have different API versions?

Note the versions: the activities endpoints run on the 202309 API version while the coupon endpoints run on 202406, so a client that assumes one version string across the promotion domain will build wrong paths for one family or the other. Pin the version per resource family and confirm each versioned path in the Partner Center docs before shipping.

How do I stop a running promotion quickly?

Deactivation is its own operation — a POST to the activities deactivate path — not a field flip on update. Treat it as your kill switch: keep the activity_id of every promotion your system created, and wire deactivation into your monitoring so a promo that is selling below floor price can be stopped in one call instead of a scramble through Seller Center.

Related Articles

Explore More