This guide is about the subscription flow itself.
For Developer API endpoints and webhook event names, use the API reference and webhook docs.
Creating a subscription product
1
Create a product
Go to Products → Create Product and select Subscription as the product type.
2
Configure billing
Set the billing interval:
- Daily — charged every day
- Weekly — charged every 7 days
- Monthly — charged on the same day each month
- Yearly — charged annually
3
Set a trial period (optional)
Offer a free trial before the first charge:
- 7-day trial
- 14-day trial
- 30-day trial
- Custom duration
What a renewal delivers
A product’srenewal_delivery (extend, new or first_only) sets what a paid renewal delivers. Each variant can override it with its own renewal_delivery; null means the variant renews like the product. Set it on POST /dev/v1/products/{id}/variants, or per variant in the variants array of PATCH /dev/v1/products/{id} (a variant sent back with its id and without the field keeps its stored value). A change applies to the next renewal of every running subscription of that variant. Only subscription products accept a value. The rules are in Subscriptions › What a renewal delivers.
Handling failed payments
Card (Stripe) and PayPal renewals are retried by the provider on its own schedule; the subscription ispast_due meanwhile and keeps access. A renewal billed by invoice (crypto, balance) has the shop’s time to pay; unpaid, the subscription goes on hold (past_due with hold_ends_at, no access) or ends, as the shop set it. Paid during the hold, a new period starts on the payment day. The rules are in Subscriptions › Renewals.
Configure retry behavior in Settings → Subscriptions.
Customer portal
Give customers control over their subscriptions through the Shoppex billing portal. Each customer receives a unique portal link in their confirmation emails where they can:- View billing history
- Update payment method
- Cancel subscription
- Download invoices
Webhooks
Subscribe to these events for subscription updates:
Shoppex supports more subscription webhook events than the short table above, including
subscription:updated, subscription:renewed, subscription:upcoming, and trial events. To gate access on webhooks, listen for subscription:past_due (with its reason and the renewal to pay), subscription:recovered, subscription:paused, subscription:resumed, subscription:trial:converted and subscription:payment_failed. See Webhook events.
See the Webhooks Guide for setup instructions.
Plan changes
Buyers change their plan in the customer portal, and merchants on the subscription detail page. Both flows read a quote first and confirm it by its id, so the amount shown is the amount charged. The rules are in Subscriptions › Plans and plan changes.- An upgrade or a move to a longer interval starts right away and charges the prorated difference, to the second. A downgrade or a move to a shorter interval starts at the next renewal and charges nothing.
- Card subscriptions are charged through Stripe (
always_invoice,pending_if_incomplete). Subscriptions billed by invoice get a change invoice that is payable for 24 hours. - While a change waits for the renewal, picking another plan replaces it: the waiting change ends, and the new one is scheduled or starts right away. Picking the current plan again is the undo.
- Shoppex sends
subscription:plan_change_scheduledwhen a change waits for the renewal, andsubscription:plan_changedonce the subscription is on the new plan and the payment that bills it is paid. See Webhook events.
DELETE /dev/v1/products/{id}/variants/{variantId} answers 409, and a variants replacement that leaves it out is refused. Set its visibility to on_hold to stop new sales: it stays listed and cannot be bought. private only hides it from listings, and a direct link (?variant=<id>) still sells it.
POST /dev/v1/subscriptions/{id}/change-plan is unchanged: it schedules a new plan of the same product and interval for the next renewal, without proration, for Stripe subscriptions that are active or in a trial. The response’s effective_at is the date the new plan starts. Until then the merchant can cancel the scheduled change on the subscription detail page. While a change is scheduled, the endpoint answers 409 plan_change_not_allowed with reason: change_scheduled; it never replaces one.
Headless / Developer API checkout
Dashboard checkout and payment links already use Shoppex subscription products. For a custom frontend or backend-driven flow, start checkout withPOST /dev/v1/orders, not POST /dev/v1/payments.
subscription:created and subscription:renewed.
Custom fields such as
plan_type: monthly do not create subscriptions by themselves. Shoppex does not read them. They are plain metadata on the invoice. Recurring billing requires a real SUBSCRIPTION catalog product and the orders checkout path.Managing subscriptions through the API
The Dev API exposes full subscription management. Here are the most common operations:Capabilities
GET /dev/v1/subscriptions/{id}/capabilities answers, for each action, whether it would go
through now. The buyer’s portal reads the same rules, so the API and the portal agree.
pause also carries the shop’s buyer pause policy (max_days, left_this_year); a pause made by
the API does not count against it. refund goes to store credit.
A capability is a check before the call, not a promise: the action still decides. When it refuses,
the error is 409 with code CONFLICT and a stable subcode, usually the same as the capability’s
reason.
Previews
The previews write nothing and take noIdempotency-Key. Times are unix seconds.
cancel/preview(cancel_at_period_end, defaultfalse):ends_at,access_until(nullwhen the buyer has no access now) anddrops_scheduled_pause.pause/preview(resume_at, optional):starts_at,resume_atandaccess_until. The pause starts at the end of the paid period, unless the shop starts pauses right away on invoice rails.change-plan/preview(new_plan_id): the quotechange-planwould confirm. It is held for 10 minutes (expires_at);change-planquotes again when it runs.
Actions
undo-cancel, cancel-plan-change and send-pay-link take an Idempotency-Key header like every
other write. send-pay-link emails the buyer the open renewal invoice and answers its pay_url, so
you can show or forward it too. cancel-plan-change takes back a change waiting for the renewal, or
voids the unpaid invoice of a change waiting for its payment.
Webhooks
Get notified about subscription lifecycle events
Invoices
Understand the invoices generated by subscriptions