- Most teams create one subaccount per merchant or segment. Then USDC balances and activity stay easy to trace in your books and in Circle reports.
- Every setup also includes a main wallet. USDC can live in the main wallet only, in subaccounts only, or across both, depending on how you fund and pay out.
Wallet structure and typical flows
The following figure is a simplified model of a Managed Payments integration with subaccounts. Circle enables only the paths that your setup and agreement support. Solid arrows are typical funding, receive, and payout paths, including payouts funded from the main wallet. Dotted arrows are optional paths your setup may use, such as a line of credit into the main wallet or moving USDC to a subaccount before payout.Accounts API
If you use the direct onboarding model, Circle handles the creation of
subaccounts for you. Submit end-merchant KYB through the Partner Onboarding
API reference, and
Circle creates subaccounts on your behalf after approval.
- Create a managed payments intermediary account when you add a merchant subaccount in the intermediary onboarding model.
- List accounts to page through subaccounts and see each one’s balances and metadata.
- Get an account to
load one subaccount’s stablecoin account by
accountId, including balances and metadata.
accountId and a walletId. Both IDs point to the
same subaccount. The accountId names the stablecoin account record. The
walletId names the wallet that holds the account’s USDC balance. API requests
and responses use one or both, depending on the endpoint.
Circle grants role-based API access when you onboard. The endpoints your API
keys can call depend on the roles set for your account.
In the intermediary model, you call the
create account
endpoint after each merchant is approved. In the direct model, Circle provisions
subaccounts during onboarding. In both cases, you reference the same accountId
values for wires, payouts, and payins.
Subaccount lifecycle
Use a subaccount’sstatus to determine whether it can process activity:
pending: Circle is creating the subaccount, but it isn’t operational yet.active: The subaccount can process supported activity.rejected: Circle rejected the subaccount creation request, and the subaccount can’t be used.archived: The subaccount is retired and excluded from account listings by default. Read requests still work, but most requests that change the account are blocked.
status=archived query parameter.
Archiving doesn’t permanently close a subaccount. An incoming deposit to an
existing deposit address or wire instruction automatically returns the
subaccount to active status. After you archive a subaccount, stop sending
funds to its existing deposit details if you intend to keep it retired.
Funding and pooled balances
Depending on your setup, USDC can be funded and spent across the main wallet and subaccounts in several ways:- Wires can credit one subaccount so that merchant’s USDC sits in its own balance. Use the Wires API for bank accounts and wire instructions.
- If your setup allows it, you can mint to a shared main wallet instead. That pool can back steady, high-volume payout use cases.
- Some setups include a line of credit. USDC may land in the main wallet first; payouts can move funds to the correct subaccount before they go onchain. Terms follow your agreement with Circle.
- Payouts usually debit a subaccount balance. If your integration supports it, you can fund payouts from the main wallet instead of from each subaccount. That helps when you send a lot and don’t want USDC in every subaccount first. Use that path only when your setup supports it.
Payins and payouts
Handle payins, debits, and reconciliation per subaccount:- Payins (receiving USDC): Each subaccount can have a stable onchain address. Create a continuous payment intent so that each merchant or segment has a dedicated receive address.
- Payouts and withdrawals: Specify the
walletIdoraccountIdof the subaccount to debit when you create a payout.
The two money-out endpoints expect different
source.type tokens for the same
subaccount: create a
payout (POST /v1/payouts) requires source.type = wallet with the walletId, while
create a
withdrawal
(POST /v1/accounts/withdrawals) requires source.type = account with the
accountId.