Assets API
Token operations on any configured chain. These endpoints work for any registered asset — replace :symbol with USDT, USDC, IMC, or any custom token — on any registered chain, EVM or Stellar, via ?chain=.
List Assets
curl -X GET "http://localhost:8100/api/v1/assets" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE"{ "assets": [{ "Symbol": "USDT", "Contract": "0x3C8E...DDDF", "Decimals": 6, "chain": "celo" }, { "Symbol": "IMC", "Contract": "0xF150...d5A2", "Decimals": 6, "chain": "celo" }], "count": 2 }List Chains
curl -X GET "http://localhost:8100/api/v1/chains" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE"{ "chains": [{ "name": "celo", "chainId": 11142220, "assets": [...] }, { "name": "stellar", "assets": [...] }], "count": 2 }stellar only appears once STELLAR_RELAYER_SEED is configured — see Setting Up Stellar →. Absent that, this instance only ever returns celo (and whatever other EVM chains are configured).
Token Balance
curl -X GET "http://localhost:8100/api/v1/assets/imc/balance?externalUserId=123&tenantSlug=comet" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE"{ "symbol": "IMC", "chain": "celo", "balance": "447000000", "decimals": 6, "humanAmount": 447 }curl -X GET "http://localhost:8100/api/v1/assets/xlm/balance?externalUserId=123&chain=stellar" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE"{ "symbol": "XLM", "chain": "stellar", "balance": "30000000", "decimals": 7, "humanAmount": 3 }Query Parameters:
| Param | Type | Required | Description |
|---|---|---|---|
externalUserId | string | Yes | Wallet owner (your own user ID) |
tenantSlug | string | No | Tenant (defaults to "comet") |
chain | string | No | Chain (defaults to "celo") — pass stellar for a Stellar-family balance |
Stellar decimals are fixed at 7
Native XLM balances are always 7 decimals — that's a Stellar protocol constant, not a per-asset setting like EVM's decimals config. Registered Stellar assets (non-native) use whatever decimals they were registered with, same as EVM.
Mint Tokens
Mints tokens directly to a user's custodial wallet using the relayer key.
curl -X POST "http://localhost:8100/api/v1/assets/imc/mint" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE" \
-d '{"externalUserId": "123", "amountBase": 10000000, "externalId": "mint-001"}'{ "amount": 10, "chain": "celo", "symbol": "IMC", "txHash": "0x..." }Request Fields:
| Field | Type | Required | Description |
|---|---|---|---|
externalUserId | string | Yes | Target user |
amountBase | number | Yes | Amount in base units (6 decimals: 1000000 = 1.0 token) |
externalId | string | Yes | Idempotency key |
Backing-aware accounting
Mints are journaled with type-aware backing. Airtime-backed assets (type: airtime) debit the airtime inventory account; all other assets debit the tenant treasury.
Works the same way with ?chain=stellar for a registered Stellar asset — minting there issues the asset (the relayer account must be the asset's issuer, per Stellar's protocol) rather than calling a token contract.
Send Tokens
Transfers tokens from a user's wallet to a recipient.
curl -X POST "http://localhost:8100/api/v1/assets/imc/send" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE" \
-d '{"externalUserId": "123", "to": "0xRecipientAddress", "amountBase": "5000000"}'{ "txHash": "0x...", "chain": "celo", "symbol": "IMC", "amount": 5 }Request Fields:
| Field | Type | Required | Description |
|---|---|---|---|
externalUserId | string | Yes | Sender |
to | string | Yes | Recipient address — an EVM 0x... address or a Stellar G... address, matching chain |
amountBase | string | Yes | Amount in base units |
On Stellar, sending to a recipient without an existing trustline for that asset establishes one automatically first (the engine signs for both sides when it custodies the recipient's wallet too).
Approve Spender
Grants an ERC-20 allowance over the user's tokens.
curl -X POST "http://localhost:8100/api/v1/assets/usdt/approve" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE" \
-d '{"externalUserId": "123", "spender": "0xSpenderAddress", "amountBase": "1000000"}'{ "txHash": "0x...", "chain": "celo", "symbol": "USDT" }If spender is omitted, defaults to the platform relayer address.
EVM only
Stellar has no allowance/approval concept — ?chain=stellar (or any non-EVM chain) returns 501 asset approval is not yet supported on "stellar" chains. Use Burn (Holder) instead, which needs no prior approval on any chain.
Burn (Relayer)
Burns tokens from a user who has approved the relayer. Used for swap-back flows.
curl -X POST "http://localhost:8100/api/v1/assets/usdt/burn" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE" \
-d '{"externalUserId": "123", "amountBase": "5000000", "externalId": "burn-001"}'{ "txHash": "0x...", "chain": "celo", "symbol": "USDT", "amount": 5 }EVM only
Same allowance dependency as Approve above — ?chain=stellar returns 501 burn-from-holder is not yet supported on "stellar" chains — use /assets/usdt/burn-by-holder instead. Use Burn (Holder) on Stellar.
Burn (Holder)
Burns tokens held by the user's own custodial wallet using the user's sealed key — no prior allowance required. Used when redeeming tokens for real-world value (e.g. burning IMC when airtime is delivered).
curl -X POST "http://localhost:8100/api/v1/assets/imc/burn-by-holder" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE" \
-d '{"externalUserId": "123", "amountBase": 3000000, "externalId": "burn-001"}'{ "txHash": "0x...", "chain": "celo", "symbol": "IMC", "amount": 3 }Request Fields:
| Field | Type | Required | Description |
|---|---|---|---|
externalUserId | string | Yes | User whose wallet holds the tokens |
amountBase | number | Yes | Amount in base units |
externalId | string | Yes | Idempotency key |
Backing-aware accounting
For airtime-backed assets, the burn credits the tenant's airtime inventory account — keeping on-chain supply pegged to real float.
This is the only burn endpoint that works on both EVM and Stellar chains — the recommended default unless you specifically need relayer-initiated burns on an EVM chain.
Admin Asset Management
Register New Asset
curl -X POST "http://localhost:8100/api/v1/admin/assets/IMC/register?chain=celo" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE" \
-d '{"contract": "0xF150E30B1C7Ab81938d650567D1454Ee0132d5A2", "decimals": 6, "name": "ImpalaCoin", "type": "airtime", "backing": "airtime"}'{ "message": "asset IMC registered on celo", "asset": { "symbol": "IMC", "contract": "0xF150...d5A2" } }curl -X POST "http://localhost:8100/api/v1/admin/assets/USDX/register?chain=stellar" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE" \
-d '{"contract": "GISSUERADDRESSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "decimals": 7, "name": "USD Stellar Token", "type": "utility"}'{ "message": "asset USDX registered on stellar", "asset": { "symbol": "USDX", "contract": "GISSUER..." } }On Stellar, contract is the asset's issuer account address (G...), not a contract address — Stellar assets are identified by (asset code, issuer), not a deployed contract.
Deregister Asset
curl -X DELETE "http://localhost:8100/api/v1/admin/assets/mytoken?chain=celo" \
-H "Content-Type: application/json" \
-H "X-Service-Token: YOUR_TOKEN_HERE"{ "message": "asset mytoken deregistered from celo" }