Documentation
Accounts and balances
How a single balance spans many chains without you reconciling by hand.
An account is the top-level container for everything you do on JuicePay. It holds balances, keys, policy rules, and the audit log. Most teams need exactly one account per legal entity.
The balance model#
The important idea is that a balance is not per chain. A balance is per asset, and it is backed by holdings spread across any number of chains.
{
"asset": "USDC",
"available": "312904.180000",
"pending": "4210.000000",
"chains": ["base", "solana", "arbitrum", "polygon"]
}Three figures matter:
| Field | Meaning |
|---|---|
available | Spendable right now, net of any in-flight outbound legs. |
pending | Inbound value seen onchain but not yet final. |
chains | Networks currently contributing to this balance. |
When you create a payout, JuicePay decides which chain to source it from. It prefers to spend from the chain holding the largest surplus so that consolidation sweeps stay small.
Sub-accounts#
Sub-accounts let you separate funds that share an account but must not be commingled — regional entities, product lines, or client money. Each sub-account has its own balances, keys, and policy rules, while the parent account keeps one consolidated view and one billing relationship.
curl -s -X POST "$JUICEPAY_URL/v1/sub_accounts" \
-H "Authorization: Bearer $JUICEPAY_KEY" \
-H "Idempotency-Key: subacct-eu-001" \
-d '{ "name": "EU Operations", "parent_behavior": "allow_transfers" }'Setting parent_behavior to isolate prevents the parent from moving funds without an explicit approval, which is usually what auditors want to see for client money.
Receive addresses#
Each sub-account has a permanent address per chain. These do not rotate; share them freely with counterparties. A single onchain deposit is credited to whichever sub-account owns the address.
Addresses are chain-specific. A USDC deposit sent on Base to a Solana address is not recoverable by JuicePay — it is a well-formed transfer to a wallet nobody controls.
To avoid that class of mistake, use payment intents rather than raw addresses whenever a customer is involved. An intent tells the payer which chains are acceptable and rejects everything else.
Sweeps#
Because holdings live on many chains, they drift. Sweeps consolidate value onto your preferred chain on a schedule you control.
{
"schedule": "0 */6 * * *",
"target_chain": "base",
"target_asset": "USDC",
"min_amount": "500.00",
"exclude_assets": ["EURC"]
}Sweeps never touch funds reserved for an in-flight payout, and they respect the min_amount floor so a $3 surplus does not trigger a $0.90 transfer.
Ledger entries#
Every movement writes at least two ledger entries. They are immutable and exportable.
curl -s "$JUICEPAY_URL/v1/ledger_entries?sub_account=sa_eu01&limit=2" \
-H "Authorization: Bearer $JUICEPAY_KEY" | jq{
"object": "list",
"data": [
{
"id": "le_7hQ2mN",
"direction": "credit",
"asset": "USDC",
"amount": "4250.000000",
"chain": "base",
"source": "payment_intent:pi_9fK2xQ",
"created": "2026-08-19T09:14:02Z"
},
{
"id": "le_7hQ2mP",
"direction": "debit",
"asset": "USDC",
"amount": "0.410000",
"chain": "base",
"source": "network_fee:pi_9fK2xQ",
"created": "2026-08-19T09:14:02Z"
}
]
}Book against these entries rather than against a bank-style running total. They are the authoritative record of what happened.