Skip to main content

Merchant Billing

Merchant Billing is the recommended integration surface for new B2B checkout and billing integrations.

Use billing when you need:

  • hosted checkout links for online orders
  • balance top-ups such as AI credits or prepaid account balance
  • managed renewal billing with customer-confirmed renewal invoices
  • products and prices managed from a catalog
  • project-scoped API keys, limits, team access, and webhooks
  • usage records linked to your customer or subscription data
Legacy API status

The old payment-intent flow remains available for existing integrations, but it should be treated as legacy and deprecated in future. New integrations should use /api/*.

Core objects

ObjectWhat it means
ProjectIsolates catalog, checkout sessions, API keys, webhooks, limits, and team access.
CustomerOptional billing identity for subscriptions, invoices, usage, and portal access. Checkout can create one automatically from customer fields.
ProductWhat you sell, such as VPN Pro, AI token pack, or SaaS Pro.
PriceHow you charge for a reusable product: one-time, balance top-up, or subscription. Optional for custom one-time payment requests.
Payment LinkReusable public entry point for a fixed project and price. Opening it is read-only; checkout is created only after buyer confirmation.
Checkout sessionOne-time hosted checkout created from a Payment Link or from your backend.
InvoiceInternal billable record created behind checkout and subscriptions. Use it for status, reconciliation, and webhooks.
SubscriptionRenewal schedule created after a subscription checkout is completed. Stendly creates renewal invoices; customers confirm renewal payments unless you build a balance-based flow.
Usage recordMetered activity for reporting or usage-based billing.
Webhook deliveryDelivery log for events sent to your backend.

Billing modes

ModeUse it forRequired price fields
one_timeOnline order, license, setup fee, single purchaseunitAmountCents, currency
balance_top_upCredits, AI tokens, prepaid balanceunitAmountCents, currency, creditAmount
subscriptionMonthly, semiannual, yearly, or other recurring product accessunitAmountCents, currency, recurringInterval, recurringIntervalCount
  1. Create or select a project in the B2B dashboard.
  2. Copy the read-only Project ID from Project Settings.
  3. Create an API key with billing:write,billing:read,payments:write,payments:read.
  4. Configure a webhook endpoint and save the signing secret immediately.
  5. Create products and prices when you need reusable catalog, balance top-ups, or managed subscriptions.
  6. Start with a Payment Link when a fixed product/price is enough.
  7. Create checkout sessions from your backend when you need trusted customer IDs, dynamic amounts, or order-specific redirects.
  8. Fulfill access only after a verified webhook event confirms payment.

Create catalog and checkout

API_KEY="st_live_or_dev_key"
PROJECT_ID="project_uuid"

curl -X POST "https://api.stendly.com/api/products" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: product-vpn-pro" \
-d '{
"projectId": "'"$PROJECT_ID"'",
"name": "VPN Pro",
"description": "Monthly VPN access"
}'
PRODUCT_ID="product_uuid"

curl -X POST "https://api.stendly.com/api/prices" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: price-vpn-pro-semiannual" \
-d '{
"projectId": "'"$PROJECT_ID"'",
"productId": "'"$PRODUCT_ID"'",
"name": "VPN Pro semiannual",
"unitAmountCents": 4999,
"currency": "USD",
"billingMode": "subscription",
"recurringInterval": "month",
"recurringIntervalCount": 6
}'

For a one-off order where your own backend already owns the cart, you can skip catalog setup and create a checkout session with amountCents, mode: "one_time", and merchantReference.

PRICE_ID="price_uuid"

curl -X POST "https://api.stendly.com/api/checkout-sessions" \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: checkout-order-1001" \
-d '{
"projectId": "'"$PROJECT_ID"'",
"priceId": "'"$PRICE_ID"'",
"mode": "subscription",
"externalCustomerId": "telegram_123456",
"customerEmail": "customer@example.com",
"merchantReference": "order_1001",
"successUrl": "https://example.com/success",
"cancelUrl": "https://example.com/cancel"
}'

Open the returned checkoutUrl on your website or inside your application.

Webhook handling

Your backend should verify X-Stendly-Signature and then update local order state by event type.

Common billing event families:

  • checkout.session.*
  • invoice.*
  • subscription.*
  • customer.balance_*
  • payment_intent.*

For production, do not collapse all event types into a single paid state. Treat checkout completion, invoice payment, subscription activation, and balance crediting according to your fulfillment rules.

Examples

The repo includes website-based billing examples:

  • examples/billing-node
  • examples/billing-python
  • examples/billing-dotnet

Each example implements one-time checkout, balance top-up, subscription checkout, catalog setup, usage recording, webhook verification, and local order status sync. The page shows what the customer receives and what the merchant should unlock after the signed webhook arrives.