PaybytokenDocs
Customer balances
Guide · Customer Balances

Build customer balances

Provision persistent deposits and maintain exact chain-and-asset customer funds.

Customer balances are for products that hold a merchant-scoped ledger for each customer. They are not checkout addresses and they are not a promise that assets on different chains are fungible.

Integration sequence

Funds movement, not browser state
PersistentDeposit addressOne address slot
Chain finalityDepositDetected → confirmed
Exact assetAvailable balanceChain + token scoped
Next movement
Payment
Withdrawal
Every balance remains scoped to one merchant, customer, chain and asset.
  1. Create one Paybytoken Customer for the authenticated customer in your system.
  2. Read /api/v1/deposit-assets and show only currently enabled chains and assets.
  3. Provision an EVM deposit account and an initial persistent address slot.
  4. Wait until the address watch is ready before displaying it.
  5. Consume signed customer_deposit.* events and retrieve balances server-side.
  6. Spend with a customer_balance Payment Intent or create a customer withdrawal.

Use @paybytoken/node or the Customer deposits API. Store Customer, deposit-account and address IDs in your backend. Never derive availability from a browser poll alone.

Provision a customer and address

Create one merchant-scoped Customer for one durable customer identity in your system. Reuse that Customer across deposits and balance payments; do not create a new Customer for every checkout.

const customer = await paybytoken.customers.create(
  {
    reference: `user:${user.id}`,
    email: user.email,
    name: user.displayName,
    metadata: { internal_user_id: user.id },
  },
  { idempotencyKey: `customer:${user.id}` },
)

const assets = await paybytoken.depositAssets.list()
const supportsBaseUsdc = assets.data.some(
  (asset) => asset.chain === 'base' && asset.asset === 'USDC' && asset.enabled,
)

if (!supportsBaseUsdc) throw new Error('Base USDC deposits are unavailable')

const account = await paybytoken.customerDepositAccounts.create(
  customer.id,
  {
    address_family: 'evm',
    initial_address: {
      label: 'Primary deposit address',
      chains: ['base'],
    },
  },
  { idempotencyKey: `deposit-account:${customer.id}:evm` },
)

Provisioning can be asynchronous. If the result has status: "provisioning", wait for the suggested retry interval and retrieve the account from your server. Display an address only after the address and requested chain are active.

An EVM address slot may be activated on another supported EVM chain later. Activation changes which chain Paybytoken watches; it does not make balances fungible across those chains.

Exact-asset accounting

Every balance is scoped to merchant, customer, mode, chain and asset. Base USDC cannot silently pay an Ethereum USDC intent. Decimal values are strings; atomic values are integer strings. Use the asset discovery endpoints for contracts, precision, minimums, maximums and fees instead of hard-coding them.

Deposits can be detected before they are finalized. Credit spendable funds only after Paybytoken marks the deposit credited. Keep below-minimum, restricted and reversed states visible to support and reconciliation workflows.

Deposit lifecycle

StatusMeaningCustomer-facing treatment
detected / confirmingTransfer was observed but has not reached required finality.Show pending; do not make funds spendable.
confirmedChain confirmation policy passed and accounting is finishing.Keep pending until credited.
creditedExact-asset available balance was updated.Funds may be used for supported balance payments or withdrawals.
below_minimumTransfer does not meet current deposit policy.Explain the limitation; do not ask for another transfer to the same transaction.
restrictedCompliance or operational policy stopped crediting.Route to support without exposing internal risk details.
reversedA previously observed chain outcome was reversed.Freeze dependent business actions and reconcile.

Persist the deposit ID and transaction hash for support, but use the Paybytoken deposit status as the accounting state. A block explorer is evidence of a transaction, not evidence that the merchant-scoped balance was credited.

Customer experience and controls

  • Show the exact chain, asset, address and minimum before the customer transfers.
  • Warn against sending from an exchange or bridge when refunds require control of the source.
  • Never combine amounts across chain and asset rows into one spendable number.
  • Keep retired addresses in history; do not silently present them as active.
  • Restrict or close a Customer through an authorized backend workflow, not a browser-only action.

Continue with Pay and withdraw from customer balances.

On this page

API Workbench

Full Explorer

Open in new tab