Skip to content

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=.

▸API ConfigurationNot configured
Every endpoint, payload, and response on this page follows this choice.

List Assets ​

List All Assets
curl -X GET "http://localhost:8100/api/v1/assets" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET"
Response200
{
  "assets": [
    {
      "Symbol": "USDT",
      "Contract": "0x3C8E...DDDF",
      "Decimals": 6,
      "chain": "celo"
    },
    {
      "Symbol": "IMC",
      "Contract": "0xF150...d5A2",
      "Decimals": 6,
      "chain": "celo"
    }
  ],
  "count": 2
}

List Chains ​

List Chains
curl -X GET "http://localhost:8100/api/v1/chains" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET"
Response200
{ "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 ​

IMC Balance (Celo)
curl -X GET "http://localhost:8100/api/v1/assets/imc/balance?externalUserId=123&tenantSlug=comet" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET"
Response200
{
  "symbol": "IMC",
  "chain": "celo",
  "balance": "447000000",
  "decimals": 6,
  "humanAmount": 447
}

Query Parameters:

ParamTypeRequiredDescription
externalUserIdstringYesWallet owner (your own user ID)
tenantSlugstringNoTenant (defaults to "comet")
chainstringNoChain (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.

IMC can't be minted here

IMC is backed by airtime and is only minted by booking an airtime top-up (POST /admin/imc/airtime-topup, see Airtime), into your IMC treasury. Every other flow moves IMC that already exists: IMM cycles, distributions, swaps and vault funding. A mint request for IMC on any other endpoint is refused.

Mint a token (Celo)
curl -X POST "http://localhost:8100/api/v1/assets/ctest/mint" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -d '{
  "externalUserId": "123",
  "amountBase": 10000000,
  "externalId": "mint-001"
}'
Response200
{
  "amount": 10,
  "chain": "celo",
  "symbol": "IMC",
  "txHash": "0x..."
}

Request Fields:

FieldTypeRequiredDescription
externalUserIdstringYesTarget user
amountBasenumberYesAmount in base units (6 decimals: 1000000 = 1.0 token)
externalIdstringYesIdempotency 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.

Stellar issues, it doesn't deploy

On Stellar, minting an asset means the relayer account (which must be that asset's registered issuer, per Stellar's protocol) makes a payment of a newly-issued amount — there's no token contract to call, unlike EVM's mint(). The response shape is identical either way; only what happens on-chain differs.


Send Tokens ​

Transfers tokens from a user's wallet to a recipient.

Send IMC (Celo)
curl -X POST "http://localhost:8100/api/v1/assets/imc/send" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -d '{
  "externalUserId": "123",
  "to": "0xe3f53fe54f8e1b5e8c86f070e4c9c2c7fa641d0d",
  "amountBase": "5000000"
}'
Response200
{
  "txHash": "0x...",
  "chain": "celo",
  "symbol": "IMC",
  "amount": 5
}

Request Fields:

FieldTypeRequiredDescription
externalUserIdstringYesSender
tostringYesRecipient address — an EVM 0x... address or a Stellar G... address, matching chain
amountBasestringYesAmount 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.

Approve USDT
curl -X POST "http://localhost:8100/api/v1/assets/usdt/approve" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -d '{
  "externalUserId": "123",
  "spender": "0xSpenderAddress",
  "amountBase": "1000000"
}'
Response200
{
  "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.

Burn USDT (Relayer)
curl -X POST "http://localhost:8100/api/v1/assets/usdt/burn" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -d '{
  "externalUserId": "123",
  "amountBase": "5000000",
  "externalId": "burn-001"
}'
Response200
{
  "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).

Burn IMC (Holder, Celo)
curl -X POST "http://localhost:8100/api/v1/assets/imc/burn-by-holder" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-API-Secret: YOUR_API_SECRET" \
  -d '{
  "externalUserId": "123",
  "amountBase": 3000000,
  "externalId": "burn-001"
}'
Response200
{
  "txHash": "0x...",
  "chain": "celo",
  "symbol": "IMC",
  "amount": 3
}

Request Fields:

FieldTypeRequiredDescription
externalUserIdstringYesUser whose wallet holds the tokens
amountBasenumberYesAmount in base units
externalIdstringYesIdempotency 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 ​

Register Asset (Celo)

🔒 Admin operation — always requires a Service Token, regardless of the panel above.

curl -X POST "http://localhost:8100/api/v1/admin/assets/IMC/register?chain=celo" \
  -H "Content-Type: application/json" \
  -H "X-Service-Token: YOUR_SERVICE_TOKEN" \
  -d '{
  "contract": "0x1D1aA006f66A191fc04e7d1cab8D62B0c81d9221",
  "decimals": 6,
  "name": "ImpalaCoin",
  "type": "airtime",
  "backing": "airtime"
}'
Response200
{
  "message": "asset IMC registered on celo",
  "asset": {
    "symbol": "IMC",
    "contract": "0xF150...d5A2"
  }
}

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 ​

Deregister Asset

🔒 Admin operation — always requires a Service Token, regardless of the panel above.

curl -X DELETE "http://localhost:8100/api/v1/admin/assets/mytoken?chain=celo" \
  -H "Content-Type: application/json" \
  -H "X-Service-Token: YOUR_SERVICE_TOKEN"
Response200
{
  "message": "asset mytoken deregistered from celo"
}

Released under the MIT License.