Skip to content

Payouts ​

A payout sends USDC on Base from the user's FluxA Wallet to an EVM address. By default the user approves each payout in FluxA Wallet. If you pass a signed mandateId with enough budget, the payout is approved automatically and needs no user action.

All endpoints require Authorization: Bearer <agent-jwt>.


Create payout ​

POST/api/payoutsBearer agent-jwt
bash
curl -X POST https://walletapi.fluxapay.xyz/api/payouts \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $AGENT_JWT" \
  -d '{
    "payoutId": "po_abc123",
    "toAddress": "0x1234567890abcdef1234567890abcdef12345678",
    "amount": "1000000",
    "mandateId": "mand_xxxxxxxxxxxx",
    "bizId": "order_20260416_001",
    "description": "Refund for order #001"
  }'

Request fields ​

FieldTypeRequiredDefaultDescription
payoutIdstringYes–Your idempotency key (max 128 chars). A repeat request with the same payoutId and the same parameters returns the existing payout.
toAddressstringYes–Destination EVM address (0x + 40 hex chars). The zero address is rejected.
amountstringYes–Positive integer string in atomic units (1000000 = 1.0 USDC).
mandateIdstringNo–A signed USDC mandate belonging to this agent. If it is active and has enough budget, the payout is approved automatically.
bizIdstringNo–Your business reference. Only one live payout per bizId is allowed (see bizId deduplication).
networkstringNobasebase or base-sepolia (CAIP-2 eip155:8453 / eip155:84532 are also accepted).
currencystringNoUSDCOnly USDC is supported.
assetAddressstringNoUSDC on the chosen networkIf you send it, it must be the USDC contract for that network (Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913).
descriptionstringNo–Memo shown to the user (max 500 characters).
metadataobjectNo–Your own JSON metadata.
ttlSecondsintegerNo604800How long the user has to approve the payout, from 60 to 604800 seconds (7 days).

Response ​

201 Created for a new payout. 200 OK for an idempotent repeat with the same payoutId and parameters.

json
{
  "payoutId": "po_abc123",
  "txHash": null,
  "approvalUrl": "https://agentwallet.fluxapay.xyz/authorize-payout/po_abc123",
  "expiresAt": 1713340800,
  "mandateId": "mand_xxxxxxxxxxxx",
  "bizId": "order_20260416_001",
  "description": "Refund for order #001"
}
FieldDescription
payoutIdYour payout ID.
txHashOn-chain transaction hash once the transfer is sent; null before that.
approvalUrlFluxA Wallet page for this payout. Without a mandate, give this link to the user so they can approve or reject the payout.
expiresAtApproval deadline (Unix seconds).
mandateIdThe mandate used for automatic approval, or null.
bizIdYour business reference, or null.
descriptionThe memo, or null.

To track the result, poll Get payout status and read displayStatus.

Error responses ​

Error bodies have an error message and, for most cases, a machine-readable code.

HTTPcodeWhen
400–A required field is missing or invalid (payoutId, toAddress, amount, bizId, mandateId, assetAddress).
400unsupported_currency / unsupported_networkThe currency or network isn't supported.
400invalid_ttl_secondsttlSeconds is outside 60–604800.
400invalid_description / description_too_longdescription isn't a string or is longer than 500 characters.
400mandate_not_signedThe user hasn't signed the mandate yet.
400mandate_disabledThe user disabled the mandate.
400mandate_expiredThe mandate is outside its validity window.
400mandate_currency_mismatchThe mandate isn't a USDC mandate.
400mandate_insufficient_budgetThe mandate's remaining budget is too small. The body includes remaining (atomic units).
401–The agent JWT is missing, invalid or expired. A VC token returns { "error": "wrong_token_type" }.
403mandate_mismatchThe mandate belongs to a different agent.
404mandate_not_foundThe mandate doesn't exist.
404–The agent isn't linked to a FluxA Wallet yet.
409–The payoutId was already used with different parameters. The body includes the existing payout.
409–The bizId is already in use. The body includes existingPayoutId.

Automatic approval with a mandate ​

When you send a mandateId, FluxA checks that the mandate:

  • belongs to this agent,
  • is signed and enabled,
  • is inside its validity window,
  • is a USDC mandate, and
  • has a remaining budget of at least amount.

If all of these pass, the payout skips user approval and starts processing right away. The amount counts against the mandate's budget. If any check fails, the request is rejected with one of the mandate_* codes above and no payout is created.


bizId deduplication ​

bizId stops your system from paying the same business item twice. Each user can have only one live payout per bizId:

  • If a payout with the same bizId is awaiting approval, processing, completed or expired, a new payout with that bizId returns 409 with existingPayoutId.
  • After a payout has failed or been rejected, you can create a new payout with the same bizId.

payoutId and bizId together ​

  • payoutId makes a single request safe to retry. The same payoutId with the same parameters returns the existing payout (200). The same payoutId with different parameters, including a different bizId, returns 409.
  • bizId deduplicates at the business level. A different payoutId with a live bizId returns 409.
  • The two are independent. You can use either, both or neither.

Get payout status ​

GET/api/payouts/:payoutIdBearer agent-jwt

See Get payout status.

Released under the MIT License.