StableOps

Checkout

Use hosted Checkout for stablecoin payments: create a session on your backend, then redirect the payer to the payment page.

Checkout is for flows where you want less frontend integration work: your backend creates a Checkout Session, then redirects the payer to the StableOps-hosted payment page. The hosted page shows chain, asset, receiving address, and order status. Your integration only needs to create sessions and handle webhooks; you do not have to build the payment UI yourself.

How to use it

  1. Create a Checkout Session on your backend: call stableops.checkoutSessions.create with your API key, merchant order ID, amount, accepted assets, display title, success URL, and cancel URL.
  2. Redirect the payer to Checkout: after creation, issue a 303 redirect to checkout.url, or return the URL to your frontend and call window.location.assign(checkout.url).
  3. Let the payer complete the transfer: the hosted page shows the chain, asset, exact amount, and receiving address, and tracks status live. The payer can pay with a browser wallet — the page connects an injected wallet and lets them choose the network automatically or manually — or use manual transfer to copy the address and send from any wallet or exchange. Scanners match the deposit either way.
  4. Complete business logic from webhooks: receive and verify payment.confirmed / payment.finalized webhook events, then provision service, post ledger entries, or update your order. Do not rely on successUrl alone; it is a browser return path, not final payment proof.

Create a session on the backend

import { StableOps } from '@stableops/api-sdk'

const stableops = new StableOps({
  apiKey: process.env.STABLEOPS_API_KEY!,
})

const merchantOrderId = 'order_123'
const checkout = await stableops.checkoutSessions.create(
  {
    merchantOrderId,
    amount: '49.00',
    amountMode: 'auto',
    acceptedAssets: [{ chain: 'base-sepolia', asset: 'USDC' }],
    title: 'Acme Pro',
    successUrl: `https://app.example.com/success?orderId=${merchantOrderId}`,
    cancelUrl: `https://app.example.com/billing?orderId=${merchantOrderId}`,
  },
  { idempotencyKey: 'order_123' },
)

return Response.redirect(checkout.url!, 303)

Parameter guidance

  • merchantOrderId: use your internal order ID, and reuse it as the idempotency key to avoid duplicate sessions.
  • amountMode: 'auto': lets StableOps adjust the amount slightly to reduce collisions on shared receiving addresses.
  • acceptedAssets: start with testnet assets, then switch to the production chains you actually support.
  • successUrl / cancelUrl: browser return paths only. Treat webhooks as the source of truth for payment state.
  • metadata: include plan, user ID, or internal labels. The public Checkout page does not expose order metadata.

Online testing

The panel below uses your sandbox API key directly in the browser to create a Checkout Session, then redirects to the public Checkout page. You can customize merchant order ID, amount, title, description, return URLs, and order metadata to see how merchant parameters appear in the payment flow.

For docs testing only. The key stays in this browser. Create Checkout Sessions on your backend in production.

Security notes

  • This panel is for sandbox testing only. In production, create Checkout Sessions on your backend and never expose a live API key in the browser.
  • The clientSecret opens the public payment page and should only be sent to the current payer.
  • The Checkout page reads only the public session. It does not require Clerk sign-in and does not expose order metadata.

Handle the webhook

Checkout settles through the same payment orders as the SDK flow, so payment state always arrives over webhooks — never trust the successUrl redirect alone.

How is this guide?

Last updated

On this page