The product lifecycle
A product moves through three states via itsstatus field:
| Status | Meaning |
|---|---|
draft | Created but not visible or purchasable. The starting state. |
active | Published and available for purchase. Requires at least one price variant. |
archived | Retired — no longer listed or purchasable, but kept for history. |
Step 1 — Create the draft product
"status": "draft" and an id like prod_abc123. Other fields you can set at creation: body_html, button_cta, available_from / available_until (date-times for scheduled availability), tax_code, and images (covered below).
Step 2 — Attach a price variant
Every price variant must reference its product:Step 3 — Publish
The price variant model
A single product can carry several price variants (a “monthly” and an “annual”, say), and each is defined by two key enums plus a handful of modifiers.amount_type — what the buyer pays
| Value | Behavior |
|---|---|
free | No charge. Used for lead magnets and free tiers. |
fixed | A set price in amount (cents). |
custom | Pay-what-you-want. The buyer chooses, bounded by minimum_amount / maximum_amount, with preset_amount as the suggested default. |
billing_type — how often they pay
| Value | Behavior |
|---|---|
one_time | A single charge. |
subscription | Recurring billing on recurring_interval (day | week | month | year) × interval_count. |
payment_plan | A fixed number of installments (installment_count) — pay in parts, then it ends. |
Modifier fields
| Field | Type | Applies to | Notes |
|---|---|---|---|
amount | int (cents) | fixed | The price. 4900 = $49.00. |
currency | string | all | Lowercase ISO, e.g. "usd". |
recurring_interval | enum | subscription | day | week | month | year. |
interval_count | int | subscription | Multiplier — e.g. month × 3 = quarterly. |
installment_count | int | payment_plan | Number of installments. |
setup_fee_amount | int (cents) | subscription / payment_plan | One-time fee charged up front. |
trial_period_days | int | subscription | Free trial length before first charge. |
revoke_after_days | int | all | Auto-revoke access N days after purchase. |
minimum_amount / maximum_amount | int (cents) | custom (PWYW) | Bounds on what a buyer may pay. |
preset_amount | int (cents) | custom (PWYW) | Suggested default amount. |
quantity_available | int | all | Caps how many can be sold — e.g. seats in a cohort or limited spots. |
waitlist | bool | all | Collect interest when sold out. |
hidden | bool | all | Hide this variant from the website (still purchasable by link). |
archived | bool | all | Retire this variant. |
The response also returns
discounted_from_amount (for showing a strike-through “was” price), benefits, purchase_url, and position (ordering among a product’s variants).Worked examples
Each example below assumes you’ve already created a draft productprod_abc123 and shows just the price variant. Remember to PATCH the product to active once at least one variant exists.
- One-time
- Monthly subscription
- Payment plan
- Pay-what-you-want
- Free lead magnet
A single $49 charge — the simplest sellable thing.
Adding images
A product’s gallery is set by passing an array of MediaLibrary file ids inimages. The first id is the cover.
file_... ids by uploading via POST /files, or by generating artwork with POST /images/generate (generated images land in your MediaLibrary automatically). Passing an empty array ("images": []) clears the gallery.
Next steps
Checkouts
Turn published price variants into payments with checkouts and checkout links.
Subscriptions & billing
Manage the subscriptions, invoices, and refunds your price variants generate.
Discounts
Add promo codes scoped to specific price variants.
Commerce overview
Step back to the full mental model of how the primitives connect.

