Concepts

Payments and gateways

Configure gateway accounts, learn how a charge is routed to one, handle 3-D Secure with payment intents, and read the record of every payment attempt.

tmbilling decides what to charge. A gateway does the charging.

The engine never imports a provider's SDK directly — each provider sits behind one adapter interface. So adding a provider does not touch billing logic, and billing logic never comes to depend on one provider's quirks.

Configure gateway accounts

Give a business as many gateway accounts as you need. Each carries encrypted credentials, the currencies it handles and the payment method types it supports, and is live or test to match its business.

GET/v1/businesses/{biz}/gateway_accounts

Know how tmbilling routes a charge

For each charge, the router selects an account by currency and method type — or uses the gateway_account_id you pass explicitly.

Leave a currency unmapped and tmbilling refuses the charge rather than routing it to whichever account happens to be configured. You would otherwise discover EUR charged through a USD account weeks later, in a reconciliation.

Store payment methods

The gateway vaults the card and returns a token. tmbilling stores that token and the non-secret descriptors.

Each method carries a status that an expiry sweep keeps current — valid, expiring, expired, invalid or pending_verification — and a role of primary, backup or none. When the primary declines, tmbilling falls through to the backups within the same attempt. Only a hard decline marks a card invalid. Hosted checkout charges only the card your buyer entered or picked.

Handle 3-D Secure with payment intents

When a card needs your buyer to authenticate, the charge becomes a two-step flow:

Create an intent

POST /payment_intents with a purpose of payment or setup. You get back a next_action describing what your buyer has to do.

Let your buyer authenticate

They complete the provider's own flow in their browser. Your key is never involved.

Consume the intent

POST /payment_intents/{pi}/consume turns the authorized intent into the actual charge.

An off-session charge that returns requires_action has nobody to ask, so tmbilling falls through to dunning and reaches your customer by email instead.

tmbilling sweeps unconsumed intents hourly and expires them.

Read the transaction log

tmbilling writes every gateway interaction as a transaction row — authorizations, payments and refunds — with the gateway's own error_code, its id at the gateway, and a status vocabulary that uses the same succeeded / failed words as payments and covers the awkward cases: timeout, needs_attention and late_failed. The older spellings success, failure and late_failure are still accepted on filters and on reconcile, and are never returned.

GET/v1/businesses/{biz}/transactions
A failed payment is a row you can list, filter and reconcile. That is what makes "why was this customer never charged?" a question you can answer.

Reconcile late failures

Providers sometimes settle asynchronously, and sometimes reverse a success hours later.

tmbilling ingests inbound provider webhooks and reconciles them against the transaction. It settles an in-progress charge, and a late failure reopens the invoice it had marked paid.

GET/v1/businesses/{biz}/gateway_webhooks
POST/v1/businesses/{biz}/gateway_webhooks/{id}/replay

tmbilling deduplicates inbound webhooks by the provider's event id, so a provider that delivers twice never settles twice.

Refund a payment

POST/v1/businesses/{biz}/payments/{pay}/refund

Refund in full or in part, against the original payment. tmbilling writes the refund as its own transaction with its own ledger entries and leaves the original payment untouched.

To refund money collected on a paid invoice, use a refundable credit note instead. It keeps the invoice, the credit and the refund tied together. See Invoices.

React to disputes

GET/v1/businesses/{biz}/disputes

tmbilling surfaces chargebacks raised at the provider as first-class objects with their own events, so your integration can react to a dispute rather than you finding it in a provider dashboard.

Copyright © 2026