- Docs
- Integrations
- Billing
Billing
Manage customers, subscriptions, and invoices with a stub, Stripe, or Paddle adapter.
billing.Billing is one facade over provider APIs for customers, subscriptions, and invoices, in minor units. Use Payments for the charge.
Quick start
Section titled “Quick start”stub is the default: zero-infra, in memory, safe in tests.
BILLING_ADAPTER=stubBILLING_SANDBOX=trueProvider keys come from shared/providersopt: secret_key (Stripe), api_key (Paddle), endpoint (absolute URL), sandbox. Env vars mirror the keys. See the billing config reference.
package main
import ( "context" "fmt"
billingstub "github.com/zenta-dev/zever/adapters/billing/stub" "github.com/zenta-dev/zever/config" "github.com/zenta-dev/zever/container")
func main() { billingstub.Register() // container wires nothing c := container.New(config.Default()) ctx := context.Background() defer c.Close(ctx)
b, err := c.Billing() if err != nil { panic(err) } cust, _ := b.CreateCustomer(ctx, "Ada", "ada@example.com", "key-1") sub, _ := b.CreateSubscription(ctx, cust.ID, "plan-pro", "key-2") inv, _ := b.GetInvoice(ctx, cust.ID) fmt.Println("customer:", cust.ID) fmt.Println("subscription:", sub.ID, string(sub.Status)) fmt.Println("invoice due:", inv.AmountDue) _ = b.Close()}Expected output with stub (IDs are cus_/sub_ plus a random ULID, so they vary):
customer: cus_01J0000000000000000000000subscription: sub_01J0000000000000000000001 activeinvoice due: 0Pass minor units and idempotency keys
Section titled “Pass minor units and idempotency keys”Amounts are int64 minor units (cents, not dollars); format with the currency exponent helpers, since not every currency has two decimals. Pass a stable idempotency key on each create so retries never double-create.
Choose an adapter
Section titled “Choose an adapter”| Adapter | Package | Notes |
|---|---|---|
stub |
adapters/billing/stub |
Default. In memory, ULID-identified records. |
stripe |
adapters/billing/stripe |
Needs secret_key. |
paddle |
adapters/billing/paddle |
Needs api_key. |
Production checklist
Section titled “Production checklist”billingis not the system of record; the provider is, giving typed create/query without per-provider HTTP.SecretKeyandAPIKeynever surface in errors or logs. Hold them in Secrets.
Troubleshooting
Section titled “Troubleshooting”Tests hit the real provider
Cause: the adapter was overridden. Fix: check BILLING_ADAPTER and the adapter field; config.Default() picks stub.
Validate rejects endpoint
Cause: a custom endpoint must be an absolute URL with scheme and host. Fix: correct the URL.
Amounts are off by a factor of 100
Cause: major units passed where minor units belong. Fix: multiply by the currency exponent (ParseMinorUnits) before create.