Access and scopes
Use an account-owned API key, the exact studio ID in each path, and an active grant for that studio. Anonymous sessions cannot manage offers. Test and Live keys select separate offer environments; a Test Mode offer does not become a Live offer. Use a Test Mode key to exercise offer writes in the isolated Test environment before making a Live change.
Studio roles also apply: owners and admins can manage offers, while other
authorized studio staff can read them.
offers:write does not imply
offers:read; give a key both scopes only when its workflow needs both.
Checkout-link creation, preparation, and recovery also require
offers:apply, alongside the checkout-link and print-order scopes.
See Checkout Links.
Routes
All routes are under/v1/studios/{studio_id} and require the exact studio
grant.
Create a code
The create request accepts a complete set of terms. It does not accept Stripe IDs, a calculated price, or a client-supplied discount amount for an order. Code values must be uppercase, contain no whitespace, and be at most 80 characters. Percentage discounts use whole percentages from 1 through 100; fixed discounts use a positive amount in cents. Currency must be USD. For a fixed amount, setkind to fixed and send amount_off_cents instead
of percent_off.
application is code for a customer-entered code or automatic for a
server-selected offer. Automatic offers must omit code. Scope can be
storewide, event, guardian, product, or package; event and guardian
scopes take their matching ID, while product and package scopes take a
sellable_ids array. limits.max_redemptions is optional and must be positive
when supplied. starts_at, ends_at, and minimum_subtotal_cents are optional.
The 201 response contains the offer and its first immutable revision:
id, revision, and revision_id for
subsequent operations.
Revise terms, then activate that revision
Terms are immutable after creation.PATCH appends a candidate revision and
does not activate it. Send the full replacement terms under terms, the
revision number you read as expected_revision, and a new idempotency key for
this mutation.
revision: 2 and revision_id: "revision_example_2". Activate it explicitly:
expected_revision returns 409 offer_conflict; read the current offer and
repeat the intended change with the current revision and a new idempotency key.
Schedule, pause, resume, or revoke
Scheduling also selects a revision.starts_at must be in the future, and
ends_at, when supplied, must be later than starts_at.
expected_revision plus an idempotency key. A short reason may be included.
To remove an offer from future use, revoke it. This action cannot be reversed:
List offers and continue a page
GET /v1/studios/{studio_id}/offers returns all offers visible to the studio;
the API does not take a status filter. Filter returned items by status when
you need a view such as active codes. For active codes, keep items where
status is active and application is code. The default page size is 50. Set limit
from 1 through 100 and pass next_cursor back as the opaque cursor query
parameter until is_done is true.
GET /v1/studios/stu_example/offers?limit=100&cursor=opaque-cursor, URL
encoding the cursor value in an HTTP client. next_cursor is null when the
page is complete.
Read redemption history
items, next_cursor, and is_done envelope.
Each item includes the offer revision, order ID when available, discount cents,
currency, status, and creation time. Status is succeeded,
partially_refunded, or refunded. Follow every cursor to read the complete
history; a single page is not a complete usage report.
Preview margin
Margin preview uses the separatemargins:read scope and the server’s current
catalog and provider-cost evidence. It is an estimate, not an order quote.
Unknown or stale costs remain marked in cost_status.
Idempotency and errors
Every create, revision, and lifecycle write requires anIdempotency-Key with
at most 200 characters. Keep the same key and exact request body when retrying
an uncertain result. Use a new key for a distinct intended mutation. Reusing a
key with different input or sending a stale revision returns
409 offer_conflict.
See Authentication, Idempotency, and
Errors.