Add or replace a quantity price break on a variant
Authorizations
A secret API key. Publishable keys cannot reach this API. A key may carry an expiry, and an expired key is refused exactly like an unknown one, with a 401 that names no reason; check the key's expires_at in the dashboard rather than inferring it from a response. When a merchant rolls a key's secret they choose a grace window of up to 3 days, and for its duration BOTH the new secret and the one it replaced authenticate, so an integration moves over on its own deploy schedule instead of at the instant the button is pressed. Move before the window closes: after it, the old secret is refused. Nothing else about this contract moves with a roll. The key keeps its id and its scopes, so the only thing an integration updates is the credential itself.
Headers
A unique key per logical write. Replaying a request with the same key returns the first response byte for byte instead of applying the write twice.
Path Parameters
Body
WHAT A SHOPPER IS CHARGED, not what they are shown. A tier is a BAND [min_quantity, max_quantity] whose amount replaces the variant's single-unit price for a line inside it. AN UPSERT KEYED ON (variant, currency, min_quantity), which is why this is a POST to the collection and answers 200 rather than 201: the write cannot say whether the band was created or replaced, and there is no detail route to point a Location at. Re-sending the same floor with a new amount REPLACES that band rather than adding a second one, so replaying converges. IT TAKES EFFECT AT THE NEXT CART RECOMPUTE. There is no active flag, no schedule and no review step, resolution happens at READ time and is never snapshotted, so carts already open re-price. Nothing is emitted: this family publishes no webhook topics, so a client mirroring quantity breaks must poll. TWO WRITES THAT SUCCEED AND CHANGE NOTHING, both answered 200. A band priced ABOVE the resolved unit price is stored, is returned by the GET, and is never charged, because the cart takes the lower of the unit price and the band: a tier meant as a quantity surcharge is inert. A band in a currency this store does not sell in is stored and inert too, because the column's foreign key is to the platform currency reference rather than to the store's enabled set, so nothing here refuses it and no cart ever resolves in that currency. id, variant_id, created_by, created_at and updated_at are refused BY NAME rather than ignored: the server mints the id and owns the timestamps, variant_id is in the path, and created_by is the audit record of the calling credential, which a client must not be able to write. amount, price, price_minor and unit_amount are refused the same way, because the admin route takes {"amount": 999} and a client copying that body would leave amount_minor at its zero value and sell the band for nothing. quantity, min_qty and max_qty are refused by name, and so is compare_at_amount_minor: a band price is not a discount off a struck-through price. Removing a band is DELETE /api/v1/variant-price-tiers/{priceTierId}, which takes write_pricing:delete on top of write_pricing.
Required. Three ASCII letters, stored and matched in LOWERCASE, so "USD" is normalised to "usd" here. The cart matches currency_code by equality, and a tier stored uppercase would be listed back to the merchant and never applied to a shopper. It travels in the body rather than the path because a tier's identity is (variant, currency, min_quantity), so the currency alone addresses no single tier. A code that is not a currency this platform knows is a 400, not a 409: no merchant action would make it succeed.
Required. The band FLOOR, not the quantity being bought. It is not defaulted to 1, because quantity 1 is always the base price, and anything below 2 is a 400. Bands for one variant and currency may NOT overlap: a body that would overlap an existing band is a 409 and writes nothing, so widening a band means removing the neighbour first.
x >= 2Required. The UNIT price inside the band, in INTEGER MINOR UNITS of currency_code (1299 is 12.99 in a two-decimal currency), not a discount off anything and not a line total. Omitting it is refused rather than defaulted to zero: zero passes the range check, and a band below the unit price is exactly what the cart charges, so the variant would sell for nothing above the quantity floor.
0 <= x <= 4503599627370496The band top, inclusive, and it must not be below min_quantity. Null is a REAL VALUE rather than an omission: it declares the open-ended top band (N or more). Absent means the same thing, because a band being written for the first time has nothing stored to leave alone.
Response
Success
