Subscriptions
Create plans, subscribe merchant users, issue invoices, and let end users pay through hosted Checkout.
StableOps subscriptions split merchant-side management from end-user payment. Your backend uses a secret key to manage plans, subscriptions, billing settings, and Portal sessions; the end user receives a Portal token, reads only their own invoices, and pays them through hosted Checkout.
Lifecycle
- Create one or more plans with an interval and amount. A plan's amount is a USD-denominated number.
- Create a subscription for your
merchantUserId. - Read the first open invoice and create a Portal session for that user.
- In the Portal context, create a Checkout session for the invoice and redirect the user to Checkout.
- Treat Webhooks and invoice status as the source of truth. The success URL is only a browser return path.
Settlement asset
Plans and invoices are not tied to a single stablecoin. The end user chooses which coin to pay with at payment time, exactly like a standalone payment order.
When an invoice is paid, StableOps builds a payment order for the invoice amount. The payment order accepts the supported stablecoins (USDC and USDT) available on the subscription billing chains. The payer picks one chain and coin in Checkout; the coin they actually send becomes the invoice's settled asset. Until that happens, the invoice asset is null because there is no settled coin yet.
The chain list comes from merchant-level subscription billing settings. Configure it in Dashboard under Subscriptions → Settings when you want to control the choices shown to payers across that environment. If accepted_chains is empty, StableOps derives the available chains from your imported receiving addresses. Each chain contributes only the stablecoins that StableOps supports on that chain, so a chain never advertises a coin it cannot receive.
Settlement model
Invoice checkout sessions wrap the invoice's own payment order. The payment order metadata includes invoice_id, and the invoice row points back to paymentOrderId. When the payment order reaches FINALIZED, StableOps settles that invoice through the same pair, backfills the invoice asset with the stablecoin the payer actually sent, and then advances the subscription state.
Roles
- Use a secret key from your backend or sandbox tooling to create plans, subscriptions, and Portal sessions.
- Use a Portal token in the end-user browser to read that user's subscription and invoices.
- Use Dashboard to manage plans, subscriptions, invoices, and merchant-level subscription settings.
Online testing
The panel below uses your sandbox API key in the browser to prepare demo plans, create a demo subscription, create a Portal session, and open the invoice in hosted Checkout.
SDK example
import { StableOps } from '@stableops/api-sdk'
const stableops = new StableOps({
apiKey: process.env.STABLEOPS_API_KEY!,
})
const plan = await stableops.merchantSubscriptions.plans.create(
{
code: 'starter',
name: 'Starter',
groupKey: 'starter',
// Amount is USD-denominated. No asset field; the end user picks USDC or USDT in Checkout.
amount: '9.00',
interval: 'month',
intervalCount: 1,
},
{ idempotencyKey: 'plan_starter' },
)
const created = await stableops.merchantSubscriptions.subscriptions.create(
{
planId: plan.id,
merchantUserId: 'user_123',
},
{ idempotencyKey: 'sub_user_123' },
)
const portalSession = await stableops.merchantSubscriptions.portalSessions.create({
merchantUserId: 'user_123',
})
const portal = stableops.portal(portalSession.portalToken)
const invoice = created.invoice!
const checkout = await portal.invoices.checkoutSession(invoice.id, {
successUrl: 'https://merchant.example/success',
cancelUrl: 'https://merchant.example/cancel',
})
return Response.redirect(checkout.checkoutUrl, 303)How is this guide?
Last updated