Promotion Codes
The Promotion Codes API lets you manage redeemable discount codes for your store.
Overview
The Promotion Codes API provides endpoints to:
- List promotion codes
- Retrieve a promotion code
- Create a promotion code
- Update a promotion code
- Archive a promotion code
A promotion code is the redeemable string a customer enters at checkout, together with the discount it applies — a fixed amount or a percentage, with optional currency, duration, redemption cap, and expiry.
Stripe connection required
Promotion codes are synchronised with Stripe. A store that is not connected
to Stripe cannot create promotion codes —
Create returns 422 until the connection is in
place. List, get, update, and archive work regardless.
Most fields are immutable after create
Once a promotion code has been created, only three fields can be changed:
active, name, and price_uuids. The discount amount/percent, currency,
duration, expiry, max redemptions, and the first_time_transaction /
minimum_amount restrictions are frozen.
To change any frozen field, archive the code and create a new one.
Status
Every promotion code carries a derived status (also usable as a list
filter):
| Status | Meaning |
|---|---|
active | Published, not hidden, and either has no expiry or the expiry is in the future |
inactive | Reversibly deactivated via PATCH {"active": false} — can be re-enabled |
expired | The expires_at date has passed |
archived | Irreversibly archived via POST /promotion-codes/{id}/archive |
An archived code with a past expiry reports archived — archive takes
precedence over expiry.
Deactivate vs. archive
There are two ways to stop a code from being redeemed:
- Deactivate —
PATCH /promotion-codes/{id}with{"active": false}. Reversible: call again with{"active": true}to re-enable. - Archive —
POST /promotion-codes/{id}/archive. Irreversible. The code is hidden from default listings and cannot be re-enabled.
Archived codes are excluded from the default list — pass ?status=archived
to see them.
Scope
A promotion code is either global (valid for any product) or product-scoped, with an optional narrower list of variant UUIDs:
{ "type": "global" }
{
"type": "product",
"product_id": "550e8400-e29b-41d4-a716-446655440000",
"price_ids": [
"550e8400-e29b-41d4-a716-446655440001"
]
}
price_ids narrows a product-scoped code to specific variants of that
product. An empty array means "all prices of the product".
The list endpoint's product_id filter is inclusive: it returns
product-scoped codes for that product plus all global codes — the
direct answer to "which promotion codes apply to product X?"