Wallets
All routes require x-api-key. Mutation routes explicitly marked as session routes also require Authorization: Bearer <session> and the API key permission shown. Responses use the standard envelope documented in Responses and errors.
Common auth failures occur before route handling: 403 for an invalid API key or missing permission, 401 for a missing/invalid required session, and 429 when the API key rate limit is exceeded.
Endpoints#
| Method | Path | Additional access |
|---|---|---|
PATCH | /v1/wallet/alias | — |
GET | /v1/wallet/default | — |
POST | /v1/wallet/default | — |
GET | /v1/wallet/list | — |
POST | /v1/wallet/external | Team admin |
GET | /v1/wallet/portfolio | — |
GET | /v1/wallet/evm/check-gas-balance | — |
GET | /v1/wallet/evm/allowance/{action} | — |
POST | /v1/wallet/evm/allowance/{action} | Session + WRITE |
DELETE | /v1/wallet/evm/allowance/{action} | Session + WRITE |
POST | /v1/wallet/evm/gas-sponsor | Session + WRITE |
Wallet records#
PATCH /v1/wallet/alias#
Updates or clears an alias after confirming that the team belongs to the API-key application and the wallet belongs to that team.
Body:
| Field | Type | Required | Constraints |
|---|---|---|---|
walletAddress | string | Yes | 1–64 characters |
teamId | UUID | Yes | — |
alias | string or null | Yes | Non-empty string, or null to clear |
Success: 200 with data: { walletAddress, teamId, alias }.
Route errors: 400 invalid body; 404 application team or wallet not found; 500 lookup/update failure.
GET /v1/wallet/default#
Query:
| Field | Type | Required | Behavior |
|---|---|---|---|
teamId | UUID | Conditional | May be omitted only when the API key itself supplies a team ID. |
The requested team must belong to the API-key application. Success: 200 with data: { defaultWallet }; defaultWallet is the stored wallet record or null.
Route errors: 400 no team ID is available; 404 application team not found; 500 retrieval failure.
POST /v1/wallet/default#
The teamId query parameter is required for this method. Body:
{
"walletAddress": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6"
}Success: 200.
{
"success": true,
"data": {
"message": "Default wallet updated successfully",
"walletAddress": "0x742d35Cc6634C0532925a3b8D4C9db96C4b4d8b6"
}
}Route errors: 400 missing teamId or invalid body; 404 application team or team wallet not found; 500 update failure.
GET /v1/wallet/list#
Exactly one scope query is required:
| Field | Type | Required | Constraints |
|---|---|---|---|
profileId | UUID | One of profileId/teamId | Mutually exclusive with teamId |
teamId | UUID | One of profileId/teamId | Mutually exclusive with profileId |
includeCompliance | string | No | Only the literal true enables compliance records |
Only valid EVM wallet records are returned. Success: 200 with data: { wallets: Wallet[], total: number }; total is the returned array length. There is no pagination.
Route errors: 400 invalid/missing scope; 500 retrieval failure.
POST /v1/wallet/external#
Creates an external wallet for an existing profile in an application-owned team. The profile’s membership must have the admin role.
| Field | Type | Required | Constraints |
|---|---|---|---|
teamId | UUID | Yes | — |
profileId | UUID | Yes | Must belong to teamId |
address | string | Yes | Valid for walletType |
walletType | enum | Yes | EVM, SVM, BTC, or FIAT |
label | string | No | — |
metadata | object | No | String keys |
Success: 201 with data: { address, walletType, profileId, teamId, alias, metadata, createdAt }.
Route errors: 400 invalid body/address; 403 profile is not a team admin; 404 team or profile not found; 409 wallet already exists in the team; 500 lookup/create failure.
GET /v1/wallet/portfolio#
wallets is a required comma-separated list of EVM addresses. Invalid entries are ignored if at least one valid address remains.
Success: 200 with an array of portfolio objects:
{
"success": true,
"data": [{
"totalUsdBalance": 1500.5,
"tokens": {
"USDC": {
"totalUsdBalance": 1000,
"totalBalance": 1000,
"tokenLogo": null,
"chains": {
"ethereum": {
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"balance": 1000,
"price": 1,
"chainLogo": null,
"chainId": 1
}
}
}
}
}]
}Route errors: 400 missing wallet list or no valid address; 500 supported-token configuration failure. Upstream balance failures for individual wallet/chain pairs are omitted rather than failing the request.
EVM gas and allowances#
GET /v1/wallet/evm/check-gas-balance#
| Query | Type | Required | Constraints |
|---|---|---|---|
wallet | string | Yes | One or more comma-separated EVM addresses |
tokenAddress | string | Yes | EVM token address |
chainSlug | string | Yes | Supported chain slug or positive numeric chain ID |
Success: 200 with one result per wallet: { wallet, minimumGasWei, nativeBalance, sufficient, difference }. A result can additionally contain error: { code, message } when estimation or balance retrieval failed; these per-wallet failures still return HTTP 200.
Route errors: 400 missing/invalid address or unsupported chain.
Allowance action values#
action accepts send, request, otc, general, all, or multiple. general requires executorAddress. Executor availability is chain-dependent.
GET /v1/wallet/evm/allowance/{action}#
| Query | Type | Required | Constraints |
|---|---|---|---|
chainId | string | Yes | Positive supported numeric chain ID |
userWallet | string | Yes | EVM address |
tokenAddress | string | Yes | EVM address |
executorAddress | string | Conditional | Required by general |
amount | string | No | Non-negative decimal token amount |
For one executor, data is { executorAddress, executorName, allowance, allowanceOk } and also includes difference when amount is supplied. For multiple executors, data is { executors: [...] }. Allowance and difference are decimal strings. Success is 200.
Route errors: 400 invalid action/query or unavailable executor; 500 client/allowance failure.
POST /v1/wallet/evm/allowance/{action}#
action must be send, request, otc, or general; all and multiple are rejected.
| Body | Type | Required | Constraints |
|---|---|---|---|
chainId | string | Yes | Positive supported numeric chain ID |
userWallet | string | Yes | EVM address |
tokenAddress | string | Yes | EVM address |
amount | number or string | Yes | Positive decimal amount, or "max" |
executorAddress | string | Conditional | Required by general |
Success is 200. If backend signing is available, data is { txHash, signed: true }. Otherwise it is { to, data, value: "0", chainId, signed: false } for client signing.
Route errors: 400 invalid action/body/executor; 401 missing profile/team context; 403 API key lacks WRITE; 500 signing/broadcast failure.
DELETE /v1/wallet/evm/allowance/{action}#
No body. Query:
| Field | Type | Required | Constraints |
|---|---|---|---|
chainId | string | Yes | Positive supported numeric chain ID |
userWallet | string | Yes | EVM address |
tokenAddress | string | Yes | Non-native EVM token address |
executorAddress | string | Conditional | Required by general |
Success is 200. data is { transactions, signed }; each transaction corresponds to an executor. Signed results contain executorAddress, txHash and success; unsigned results contain to, encoded data, value, chainId, and executorAddress.
Route errors: 400 invalid action/query/executor; 401 missing profile/team context; 403 API key lacks WRITE.
POST /v1/wallet/evm/gas-sponsor#
Uses the current session profile/team and only accepts a wallet owned by that profile.
| Body | Type | Required | Constraints |
|---|---|---|---|
walletAddress | string | Yes | EVM address owned by current profile |
action | enum | Yes | send or otc |
tokenAddress | string | Yes | Accepted EVM token |
chainSlug | string | Yes | Supported chain slug or numeric chain ID encoded as a string |
executeWithOwnGas | boolean | No | Defaults to false |
There is a five-minute cooldown per session user. Success is 200 and has one of three stable forms:
- no sponsorship needed:
{ message, walletBalance, requiredGas, gasPrice, executeWithOwnGas: false, gasSponsored: false }; - backend-signed approval:
{ transferTxHash, approveTxHash, gasEstimated, gasTransferred, gasPrice, gasSponsored, tokenAddress, chainSlug, action }; - external-wallet flow:
{ transferTxHash, unsignedApproveTx, gasPrice, gasSponsored, tokenAddress, chainSlug, action, message }.
Route errors: 400 invalid body, wallet/token/chain/action, sponsorship disabled, or sponsorship limit exceeded; 401 missing session profile/team; 403 API key lacks WRITE; 409 existing/sufficient allowance or another unfulfilled sponsorship; 429 cooldown active; 500 chain, pricing, signing, transfer, or transaction preparation failure.