How billing works
Read this once and the rest of the API will feel inevitable.
The object graph
Product ──┐ ├── Plan ──┐Component ┘ ├── Subscription ── Invoice ── Payment │ │ │ │ │ └─ Usage event │ └─ Refund │ │ Customer ───── Payment ──────┘ methodSix objects do the work:
- Product — what you sell. A SKU, basically.
- Plan — how you price it. Carries currency, interval, and one or more components (each with its own pricing model).
- Customer — the buyer. Owns payment methods and subscriptions.
- Subscription — a customer on a plan, recurring on the plan’s interval.
- Invoice — the bill produced when a billing period closes (or on demand).
- Payment — the attempt to collect that invoice via a payment method.
Two satellites:
- Usage event — for metered components, you push counted events; we aggregate at period close.
- Refund / Credit note — the reverse motion when something needs to be unwound.
The lifecycle in one paragraph
A customer subscribes to a plan. Paylera advances the subscription through
its FSM (pending_activation → trialing → active → …). At each
billing period boundary, the invoice engine prices line items, applies
discounts, computes tax, and finalises an invoice. A payment is then
initiated through your configured provider; it advances through its own
FSM (pending → processing → requires_action → succeeded /
failed / charged_back). If the payment fails, the dunning engine
schedules retries per your policy. If it succeeds, the revenue
recognition engine schedules deferred revenue across the service period
and posts it to the ledger as it earns. Every state change emits a
webhook event so your system can react.
Idempotency, by default
Every money-moving and resource-creating route requires an
Idempotency-Key header. If you retry the same key with the same body,
you get the original response back — no duplicate customer, no duplicate
charge. Keys are scoped per-tenant per-route and live for 24 hours. See
Idempotency.
Events, not polling
You don’t poll /v1/subscriptions/{id} waiting for active. You register
a webhook endpoint and react to subscription.activated. Events are typed,
signed, ordered per aggregate, and delivered at-least-once.
The full event catalog is at Webhooks → Event catalog.
Money is typed
Every monetary value carries an explicit currency:
{ "amount": "29.00", "currency": "USD" }Strings, not floats — financial code uses decimal arithmetic. Rounding is per-line at the currency’s minor units. We never compare amounts as strings. See Money & currency.
Multi-tenancy
Your API key resolves to exactly one tenant. There is no cross-tenant API in the public surface. Every read is filtered by your tenant; every write is recorded against your tenant. If you operate multiple brands or legal entities, you’ll get one tenant per brand and a separate API key for each.
What you’ll never have to think about
- Race conditions between webhook delivery and your business logic — the
envelope carries an
event_idyou can dedupe on. - Out-of-order events for the same aggregate — events for one subscription / invoice / payment arrive in commit order.
- FX precision drift — invoices carry the locked rate; the ledger has an explicit FX-gain/loss leg.
- Whether a refund needs a credit note — refunds emit one automatically.
- Whether a finalised invoice can be edited — it can’t. Issue a credit note.
Where to next
- Quickstart — make the first call.
- Products & plans — model your catalog.
- Subscriptions — the FSM, in plain language.