BuffMoneyBuffMoney
Foundations

Concepts & data model.

Seven objects make up the BuffMoney runtime. Every integration touches the first three; the rest are server-managed on your behalf.

How money flows

  1. 1Your backend POSTs usage events as they happen — one per metered action.
  2. 2Monthly cron groups events by (customer, contract) and locks an FX snapshot.
  3. 3The cron emits an invoice — subtotal in pricing currency, collection amount in CNY.
  4. 4Merchant or end-customer hits the checkout endpoint; we mint a payment order against WeChat / Alipay.
  5. 5Consumer pays. Channel webhook arrives. We post the CNY collection + FX conversion to the append-only ledger.
  6. 6End of month, finance closes a settlement batch — two-admin approval, FX-cleared payout in your settlement currency.

Object glossary

Usage event

One metered action — tokens, agent run, image, GB-day. Carries metric, quantity, customerExternalId, idempotencyKey, occurredAt.

Customer

Your end-user. We don't process their identity — just hold the externalId you reference.

Product + rate card

Product is the thing you sell. Rate card binds metrics → unit size → unit price minor. Versioned + locked into invoices.

Contract

Binds (customer, product, rate card) with a billing cycle. Usage events attach automatically via the customer.

FX snapshot

Locked exchange rate at invoice generation time. Same snapshot is used to compute CNY collection + USD net settlement.

Invoice

Subtotal in pricing currency, collection in CNY, fee, net settlement. Transitions: draft → finalized → paid (or void / refunded).

Payment order

One per checkout attempt. Lives on WeChat or Alipay side. Channel webhook flips status to paid / failed / refunded.

Ledger entry

Append-only double-entry record. Each transaction (collection, fee, FX, payout) has matched debit + credit rows.

Settlement batch

Monthly close per settlement currency. Two-admin approval, then FX-cleared transfer to your bank.

Invariants

  • Every business row carries merchantId — multi-tenant isolation at the data layer.
  • All monetary amounts are bigint serialized as strings in minor units.
  • FX rates are decimal strings; never JS floats.
  • Ledger entries are append-only; balance is SUM(credit) − SUM(debit), never patched.
  • Idempotency keys dedupe usage events; (merchantId, idempotencyKey) is unique.