Skip to main content
This page covers billing.io’s internal architecture. You don’t need to read this to integrate — start with the Quickstart instead.

Non-custodial model

billing.io is non-custodial. Payments flow directly from customers to your wallets on-chain. billing.io orchestrates the payment flow and monitors the blockchain — fees are charged separately via Stripe, not deducted from payments.

Core Domains

billing.io is organized into four core domains, each handling a distinct part of the payment lifecycle.
+------------------+     +-------------------+     +------------------+     +-----------------+
|    Payments      |     |  Subscriptions    |     |     Payouts      |     |    Revenue      |
|------------------|     |-------------------|     |------------------|     |-----------------|
| Payment Methods  |     | Plans             |     | Payout Intents   |     | Revenue Events  |
| Checkouts        |---->| Subscriptions     |---->| Settlements      |---->| Accounting      |
| Payment Links    |     | Renewals          |     | Reconciliation   |     | Adjustments     |
|                  |     | Entitlements      |     |                  |     |                 |
+------------------+     +-------------------+     +------------------+     +-----------------+
The entry point for all money flow. Payment Methods define how you receive crypto (chain + token + wallet + rules). Checkouts are individual payment sessions. Payment Links are shareable URLs that generate checkouts on the fly.
Recurring billing for your customers. Plans define the terms (amount, interval, token). Subscriptions track the customer-plan relationship through a full lifecycle. Renewals handle each billing period. Entitlements let you gate features per plan.
Non-custodial payout orchestration. You define Payout Intents, execute them from your own wallet, and the chain-watcher verifies Settlements on-chain. Reconciliation matches intents to settlements.
Complete financial tracking. Revenue Events form an immutable ledger. Accounting provides period summaries. Adjustments handle credits, debits, and chargebacks.

Multi-tenancy

Every resource is scoped to an organization via org_id. Row Level Security (RLS) enforces isolation at the database level — you can only access data belonging to your organization.

Environment Isolation

Every resource has an environment column set to either live or sandbox. These environments are completely isolated — sandbox data never appears in live views and vice versa.
FeatureLiveSandbox
Real blockchain transactionsYesSimulated
Stripe billingChargedFree
Payment confirmationsChain-watcherSimulated via API
Data isolationFullFull
API endpointsSameSame
Toggle between environments using the Live/Sandbox switch in the dashboard. All API endpoints behave identically in both environments, so you can build and test with confidence before going live.

Chain-Watcher Integration

The chain-watcher is a Go service that monitors supported blockchains for transaction activity. It connects to billing.io through authenticated internal endpoints.
1

Transaction Detected

The chain-watcher monitors on-chain activity for addresses associated with active checkouts and payout intents.
2

Confirmation Tracking

Once a transaction is detected, the chain-watcher tracks block confirmations until the required threshold is met.
3

Callback to billing.io

The chain-watcher calls internal endpoints (authenticated via CHAIN_WATCHER_SECRET Bearer token) to report:
  • Payment confirmationsPOST /api/billing/record-usage
  • Settlement verificationPOST /api/billing/verify-settlement
  • Subscription renewalsPOST /api/billing/subscription-renewal
4

State Update

billing.io updates the relevant records (checkout, payout intent, subscription), creates revenue events, and reports usage to Stripe.

ID Prefix Convention

All billing.io resources use prefixed IDs for easy identification. IDs are generated with 24 random hex characters (12 bytes of entropy).
EntityPrefixExample
Payment Methodpm_pm_a1b2c3d4e5f6a1b2c3d4e5f6
Customercus_cus_a1b2c3d4e5f6a1b2c3d4e5f6
Subscriptionsub_sub_a1b2c3d4e5f6a1b2c3d4e5f6
Subscription Planplan_plan_a1b2c3d4e5f6a1b2c3d4e5f6
Payout Intentpo_po_a1b2c3d4e5f6a1b2c3d4e5f6
Settlementstl_stl_a1b2c3d4e5f6a1b2c3d4e5f6
Revenue Eventrev_rev_a1b2c3d4e5f6a1b2c3d4e5f6
Adjustmentadj_adj_a1b2c3d4e5f6a1b2c3d4e5f6
Payment Linkpl_pl_a1b2c3d4e5f6a1b2c3d4e5f6
Checkoutchk_chk_a1b2c3d4e5f6a1b2c3d4e5f6
Prefixed IDs make it easy to identify resource types in logs, URLs, and support requests. When contacting support, sharing the full prefixed ID helps us locate your resource instantly.

Working with prefixed IDs

Node.js
// Parse resource type from a billing.io ID
function getResourceType(id) {
  const prefixMap = {
    pm_: "payment_method",
    cus_: "customer",
    sub_: "subscription",
    plan_: "subscription_plan",
    po_: "payout_intent",
    stl_: "settlement",
    rev_: "revenue_event",
    adj_: "adjustment",
    pl_: "payment_link",
    chk_: "checkout",
  };
  for (const [prefix, type] of Object.entries(prefixMap)) {
    if (id.startsWith(prefix)) return type;
  }
  return "unknown";
}

console.log(getResourceType("chk_a1b2c3d4e5f6"));
// => "checkout"

Environment-aware API calls

Node.js
// Use sk_test_ keys for sandbox, sk_live_ for production
const billing = new BillingIO({
  apiKey: process.env.NODE_ENV === "production"
    ? process.env.BILLING_LIVE_KEY    // sk_live_...
    : process.env.BILLING_TEST_KEY,   // sk_test_...
});

// Same API calls work in both environments
const checkout = await billing.checkouts.create({
  amount_usd: 49.99,
  chain: "tron",
  token: "USDT",
});
// In sandbox: payment is simulated
// In production: real on-chain monitoring

Supported chains

See the Introduction for the current list of supported chains and tokens. All tokens are USD-pegged stablecoins — no exchange rate risk.

Data flow

The end-to-end flow from checkout creation to revenue recording:
Checkout created (pending)
  → Customer sends crypto to merchant wallet
  → Chain-watcher detects transaction (detected → confirming)
  → Required confirmations reached (confirmed)
  → Usage reported to Stripe (orchestration fee tracked)
  → Revenue event created (immutable ledger entry)
  → Accounting period updated