A token pool API coordinates balances and movements across digital assets such as stablecoins, network tokens, tokenized assets, or internal settlement units. The architecture must make a critical distinction: an API ledger is not automatically the same thing as onchain ownership, and a displayed balance is not proof of custody. The system should state who controls keys, where assets are held, when a transfer is final, and which legal or operational entity is responsible.
This guide focuses on system design, not investment advice. A production implementation needs legal, compliance, security, accounting, and custody review appropriate to its jurisdiction and use case. The API can make boundaries explicit, but it cannot turn an unreviewed wallet design into a safe financial product.
Separate asset, account, wallet, and ledger layers
Keep balances and custody distinct
The asset layer identifies what is being measured: asset code, issuer or contract, network, decimals, and status. The wallet layer identifies where onchain assets can be controlled or observed. The account layer represents a customer, organization, treasury, campaign, or settlement pool. The ledger records credits and debits attributed to those accounts. A single account may map to one wallet, many wallets, an omnibus wallet, or no wallet at all for offchain-only units.
Do not use a ticker alone as an identifier. The same symbol can exist on several networks or refer to unrelated contracts. Use a canonical asset identifier that includes network and contract or issuer context. Preserve the original chain transaction identifier and amount in base units. Convert for display at the edge, not in the source ledger.
State the custody model
In a self-custody model, the user controls keys and the API prepares or observes transactions. In a custodial model, the operator or provider controls keys and authorizes movements. An omnibus model pools onchain assets while an internal ledger assigns beneficial balances. A segregated model maintains distinct addresses or wallets. Each model changes security, reconciliation, privacy, compliance, and failure behavior.
The API should expose the model in plain language and machine-readable fields where useful. Never suggest that an internal ledger entry is an onchain transfer. Distinguish pending deposit, detected transaction, confirmed deposit, available balance, reserved amount, submitted withdrawal, confirmed withdrawal, failed transfer, and reversed or adjusted ledger entry.
Treat stablecoins as issuer- and network-specific assets
Stablecoins can share a target denomination while differing in issuer, network support, contract behavior, compliance controls, redemption path, and operational risk. Circle’s developer documentation describes APIs for USDC balances, payments, transfers, and related products; its official API reference is an example of keeping asset operations and authentication explicit. A generic token pool should preserve those provider-specific requirements rather than implying that all dollar-denominated tokens are identical.
Keep a supported-asset registry with status, decimals, network, deposit and withdrawal availability, minimums, confirmation policy, and provider route. Version changes. When an asset or network is paused, existing balances remain visible while new operations are blocked according to policy. Clients need a stable reason code and a clear distinction between temporary maintenance and permanent retirement.
Use double-entry accounting for value movement
A double-entry ledger records every value movement as balanced debits and credits between accounts. Deposits move value from a settlement or pending account into a customer account after confirmation. Withdrawals reserve value, then move it into an outgoing settlement account when submitted. Fees go to a fee account rather than disappearing from the transaction. Corrections use compensating entries.
Store amounts as integers in the asset’s smallest unit or fixed-precision decimals with strict scale. Never use binary floating point. Every entry should reference an operation, actor, idempotency key, asset identifier, and timestamp. Ledger balance, reserved balance, and available balance are different values and should be returned separately.
Model deposits as observed events plus policy
An address may receive a transaction, but availability depends on validation. Confirm the asset contract, destination, amount, network, and required finality. Screen or review transactions where required. Handle unsupported assets and wrong-network deposits through a defined exception process rather than silently crediting an approximate value. Deposit identifiers should be stable even if the same transaction contains several transfers.
Confirmation policy varies by network and risk tolerance. Do not hard-code one number into every asset. Record observed block, confirmations or finality state, and the policy version used to make funds available. Reorganizations or provider corrections require reversal logic. A deposit can be “seen” without being spendable.
Reserve before sending a withdrawal
Reserve, sign, broadcast, reconcile
A withdrawal request first validates authorization, destination, asset support, amount, policy, and available balance. It then creates an atomic reservation. Approval, screening, and signing can occur afterward without exposing the funds to another concurrent request. Once a transaction is submitted, commit the reservation into an outgoing ledger movement and track the network state separately.
Use idempotency keys so retrying a withdrawal request cannot create a second transfer. Separate client request identifier, internal operation identifier, signing job, provider transfer identifier, and chain transaction identifier. Each serves a different purpose. Never infer failure solely from a client timeout; the operation may have progressed after the connection closed.
Define settlement and finality
“Settled” can mean posted to an internal ledger, accepted by a provider, included onchain, finalized by network policy, or redeemable through an issuer. Pick precise states and expose them. For cross-network or cross-provider flows, model each leg and its dependency. A user-facing aggregate status can summarize, but operators need the full state machine.
Reconciliation compares internal ledger entries, wallet balances, provider statements, and chain observations. Run it continuously or on a frequent schedule. Differences should create cases, not automatic balance edits. Common causes include delayed callbacks, provider fees, chain reorganizations, unsupported token receipts, decimal errors, and duplicate event processing.
Keep keys outside the general API service
Signing should occur in a hardened wallet or key-management component with narrow policy. The general pool API submits an authorized signing request; it should not read raw private keys. Use multi-party approval or threshold controls where appropriate. Separate hot operational limits from larger treasury storage. Rotate API and provider credentials independently from wallet keys.
Policies can limit amount, asset, destination allowlist, velocity, time, tenant, and required approval. A compromised application key should not be able to drain the entire pool. Every signing decision and policy override needs an audit record. Logs must not contain seed phrases, private keys, full authentication tokens, or sensitive personal data.
Treat provider events as untrusted input
Verify webhook signatures, timestamps, and endpoint secrets. Store the raw event securely, deduplicate by provider event identifier, and process it through an idempotent state transition. Events can arrive late, more than once, or out of order. When a critical event is missing, query the provider or network source of truth rather than guessing.
Do not allow a webhook payload to choose an arbitrary internal account. Map provider identifiers through your own trusted records. Validate asset, amount, and operation state before posting ledger entries. A duplicate “confirmed” event should return the existing result without a second credit.
A clear token-pool surface
GET /assets
GET /asset-accounts/{id}/balances
GET /asset-accounts/{id}/ledger-entries
POST /deposit-addresses
GET /deposits/{id}
POST /withdrawal-requests
GET /withdrawal-requests/{id}
POST /transfers
GET /reconciliation-runs/{id}
Responses should identify asset, network, amount in base and display units, state, timestamps, account, operation, and related external identifiers. Sensitive destination or identity fields may need masking by role. Use cursor pagination and stable ordering for ledger queries.
Make policy hooks explicit
Depending on the product and jurisdiction, operations may require identity checks, sanctions screening, transaction monitoring, travel-rule data, consumer disclosures, licensing, tax reporting, or restrictions on asset and geography. The API should expose policy states such as pending review, approved, rejected, or additional information required without leaking internal screening logic.
Keep compliance decisions versioned and auditable. Manual reviewers should act through scoped tools that create signed decisions, not by editing database rows. Do not mix a reversible internal approval with an irreversible onchain action until every required gate has passed.
The boundary is the product
A token or stablecoin pool API is trustworthy when it clearly separates the asset registry, wallet control, internal ledger, and settlement state. Use double-entry accounting, atomic reservations, idempotent operations, narrow signing authority, and continuous reconciliation. Preserve provider and network details rather than flattening them into a vague balance.
Review the broader Asset & Token Pools hub and the reliability patterns in webhook endpoint pools.



