Appearance
Fund and withdraw collateral
A cardholder's cards share a collateral balance. You can fund it by sending an accepted token to the application's deposit address, or ask Agio to transfer funds from your configured treasury. Treasury-managed collateral can also be withdrawn back to that treasury.
Direct deposit
Read the funding address from the card application. Wait until deposit_address and deposit_chain_id are populated; do not substitute the collateral-admin wallet_address or a personal wallet.
graphql
query DepositAddress($applicationId: Int!) {
AgioCard_card_application(where: { id: { _eq: $applicationId } }, limit: 1) {
id
card_user_id
application_status
deposit_address
deposit_chain_id
}
}json
{ "applicationId": 42 }Send the token accepted by your program to deposit_address on deposit_chain_id. Confirm the token contract with Agio during setup. Production collateral commonly uses USDC on Base (8453); development can use Ethereum Sepolia (11155111) or Base Sepolia (84532) and test tokens such as rUSD. Read the actual application chain rather than hardcoding the example network.
A deposit address is the collateral destination, separate from the wallet that administers it. Both treasury-managed and customer-supplied collateral-admin applications can receive a deposit address after contract provisioning.
After confirmation on-chain, check both the deposited token balance and resulting spending power. A confirmed transfer does not by itself establish that the issuer has credited the cardholder.
Check balances
The read surfaces use different units:
| Surface | Units |
|---|---|
AgioCard_vw_card_token_balance.token_balance | Token units |
AgioCard_vw_card_token_balance.token_balance_usd | USD |
AgioCard_vw_card_user_balance monetary fields | Integer cents |
cardBalance.balance monetary fields | USD |
Funding and withdrawal amountCents | Integer cents |
For example, spending power of $15.71 is 15.71 in cardBalance and 1571 in AgioCard_vw_card_user_balance.spending_power.
graphql
query CollateralBalances($where: AgioCard_vw_card_token_balance_bool_exp!) {
AgioCard_vw_card_token_balance(where: $where) {
deposit_address
chain_name
token_symbol
token_balance
token_balance_usd
advance_rate
}
}json
{ "where": { "deposit_address": { "_eq": "<application deposit_address>" } } }The balance view shows the collateral held on-chain. advance_rate records how much of the collateral's value can contribute to credit.
graphql
query SpendingBalance($cardUserId: String!) {
AgioCard_vw_card_user_balance(where: { card_user_id: { _eq: $cardUserId } }) {
card_user_id
credit_limit
collateral_balance
spending_power
balance_due
}
}json
{ "cardUserId": "<cardUserId from createPartnerCardUser>" }Use the numeric Agio card ID for a live issuer balance:
graphql
query LiveBalance($cardId: Int!) {
cardBalance(cardId: $cardId) {
success
id
balance {
creditLimit
pendingCharges
postedCharges
spendingPower
balanceDue
}
error
}
}json
{ "cardId": 86 }Pending authorizations reduce spending power before a purchase settles. Use transaction events to explain changes to the cardholder.
Fund from treasury
cardFundSubClientFromTreasury transfers configured collateral from your treasury into a cardholder's collateral contract. Agio signs the transfer. The treasury configuration determines the chain; there is no chainId input.
Supply the cardUserId returned by createPartnerCardUser as externalUserId. The same UUID appears as card_user_id on the cardholder and as cardApplicationExternalId on the application.
graphql
mutation Fund($input: CardFundSubClientFromTreasuryInput!) {
cardFundSubClientFromTreasury(input: $input) {
success
jobId
errorCode
error
}
}json
{ "input": { "externalUserId": "<cardUserId from createPartnerCardUser>", "amountCents": 50000 } }50000 funds $500. success: true means the job was queued, not that funds arrived. Save jobId and poll it. Enqueue-time failures include INVALID_AMOUNT, SUBCLIENT_NOT_FOUND, and TREASURY_NOT_CONFIGURED.
Poll funding status
graphql
query FundingStatus($jobId: String!) {
cardFundSubClientStatus(jobId: $jobId) {
success
jobId
status
txHash
failedCode
failedReason
attempts
errorCode
errorMessage
}
}json
{ "jobId": "<funding jobId>" }| Status | Action |
|---|---|
pending, running | Wait and poll again |
submitted | Transfer may be on-chain; keep checking the existing job |
completed | Store txHash and confirm the cardholder's balance |
failed | Read failedCode and failedReason; resolve the failure before another funding request |
failedCode reports worker failures such as COLLATERAL_CONTRACT_NOT_READY, TREASURY_WALLET_MISMATCH, or TREASURY_NOT_CONFIGURED. COLLATERAL_CONTRACT_NOT_READY means the cardholder's collateral contract did not exist yet; check status with cardFundSubClientStatus and submit again later. The query's errorCode reports a failure to read the job itself, such as NOT_FOUND; it is separate from the transfer outcome.
Uncertain transfer outcome
A job can remain submitted with failedCode: "FUNDING_SEND_INDETERMINATE" after an uncertain broadcast. Do not enqueue another funding request: the first transfer may have landed. Reconcile its transaction and collateral history or contact Agio. Funding does not have a caller-supplied idempotency key.
Withdraw to treasury
cardWithdrawForPartner withdraws collateral into your configured treasury wallet. The treasury must be the cardholder's collateral admin, as configured with createWallet: true during application setup. It cannot sign a withdrawal from a customer's self-custody collateral admin.
The destination is fixed by your treasury configuration. The request has no destination-address field. Unlike treasury funding, this operation returns its on-chain result directly.
graphql
mutation Withdraw($input: CardWithdrawForPartnerInput!) {
cardWithdrawForPartner(input: $input) {
success
transactionHash
spendingPowerCents
requestedCents
retryAfterSec
errorCode
error
}
}json
{
"input": {
"externalUserId": "<cardUserId from createPartnerCardUser>",
"amountCents": 50000,
"dryRun": true
}
}dryRun: true checks inputs, scope, treasury configuration and issuer spending power only. It does not simulate the on-chain withdrawal, so a passing dry run does not guarantee the real call succeeds. An on-chain failure returns success: false with an error message and no errorCode. Read spendingPowerCents when present; a dry run does not reserve funds or guarantee that a later withdrawal succeeds. To submit, use the same operation with dryRun: false. Store transactionHash on success and reconcile the collateral decrease.
An optional chainId defaults to the treasury's configured chain. Use a chain configured for your program. The optional vasp field supports a receiving-VASP Travel Rule integration; coordinate that setup with Agio if you need it.
| Error code | Action |
|---|---|
INVALID_AMOUNT | Supply a positive integer amountCents |
SUBCLIENT_NOT_FOUND | Check the cardUserId and partner scope |
TREASURY_NOT_CONFIGURED | Contact Agio to configure the treasury |
INSUFFICIENT_SPENDING_POWER | Compare spendingPowerCents with requestedCents |
CARD_SIGNING_IN_FLIGHT | Wait for retryAfterSec before retrying |
INTERNAL_ERROR | Check configuration and reconcile any uncertain outcome with Agio |
For bulk funding, multisend sends from a smart wallet to several deposit addresses in one batch. Collateral webhooks report deposits and withdrawals without an individual card ID.