Qubit Exchange

API reference

Base URL on a local instance: http://localhost:8710. JSON in, JSON out. Errors return { "error": "..." } with a 4xx status for client mistakes and 5xx only when something on our side broke.

POST /v1/quote

{
  "srcChain": "arbitrum", "dstChain": "base",
  "srcSymbol": "USDC", "dstSymbol": "USDC",
  "amount": "250",
  "sender": "0x…",
  "recipient": "0x…",
  "privacy": "basic",
  "firm": false,
  "providers": ["cctp", "relay"]
}

amount is a decimal string in whole tokens. sender unlocks executable calldata and allowance checks. privacy restricts the answer to confidential providers. firm creates a real order where a provider needs one — Intents and Houdini issue a one-time deposit address — so send it only when the user is about to pay. providers narrows the fan-out.

Response is { routes, notes }. notes explains which providers had nothing and why.

Each route:

FieldMeaning
provider, mode, privaterail, sub-mode, confidentiality
amountIn, amountOutsmallest units, decimal strings
amountOutFormattedhuman amount for display
amountOutUsd, nativeFeeUsd, netUsdvaluation and ranking basis
rank, rankedByposition and whether sorting used netUsd or amountOut
fees.providerBps, fees.providerNative, fees.notethe provider's own fee
points{ points, base, multiplier, season } — what this route earns
etaSecondsprovider's delivery estimate
steps[]what to execute, in order
metaprovider-specific handles: requestId, depositAddress, houdiniId, minReceiveAmount

Step kinds: approve (only when allowance is short; optional when the provider may not need it), tx (send to, data, value on step.chain), transfer (send amount of token to a deposit address), solana-tx (base64 versioned transaction), relay (Qubit's relayer finishes the job).

GET /v1/status

ProviderQuery
intents?provider=intents&depositAddress=…
cctp?provider=cctp&src=arbitrum&burnTx=0x…
relay?provider=relay&requestId=…
lifi, gaszip, lzoft?provider=…&tx=0x…
okxdex, kyber?provider=…&chain=base&tx=0x…
houdini?provider=houdini&houdiniId=…

Relayer

POST /v1/relay { srcChain, dstChain, burnTx } registers a CCTP burn addressed to QubitGate; the relayer verifies the mint recipient, simulates and delivers. GET /v1/relay?src=…&burnTx=… returns { state, iris, relayTx } where state moves waiting_attestation → relaying → done, or failed, rejected, expired.

Points

EndpointPurpose
GET /v1/points/nonce?address=returns { nonce, message } to sign
POST /v1/points/bind{ address, signature, refCode?, profileAddress?, username? } — binds a wallet; profileAddress adds it to an existing profile
GET /v1/points/profile?address=totals, rank, multipliers, wallets, recent accruals
POST /v1/points/track{ route, txHash, wallet } after signing; the indexer confirms on chain
GET /v1/points/leaderboard?limit=&offset=top profiles

Signatures are EIP-191 for EVM and ed25519 for Solana, with the signature base58-encoded. A nonce is valid for ten minutes.

Lists

GET /v1/chains — networks, public RPC endpoints and which providers serve each. GET /v1/tokens?chain=base — tokens merged by contract address across catalogues. GET /v1/health — version and the list of enabled providers.

Limits and freshness

Rate limits apply per IP. Quotes go stale in about thirty seconds; re-quote before signing if more time has passed. Never round the decimal strings — they are exact on-chain amounts, and dollar figures are for display and ranking only.