Data
API reference
Two endpoints, both public, both the same ones the interface itself calls. They read the chain and build calldata. They never hold a key, never sign anything and never see funds.
No authentication and no rate plan. There is also no stability promise yet: these routes exist to serve this site, and a field can change while the product is unfinished.
GET /api/quote?list=1
What can actually be routed right now. Add &token=EURC to ask about one asset.
curl "https://app.usespecie.xyz/api/quote?list=1&token=EURC"| Field | Meaning |
|---|---|
| tokens[].symbol | the asset, always quoted against USDC |
| tokens[].tradable | a pool with liquidity exists and prices a small order |
| tokens[].smallOnly | a thousand unit order cannot be filled near the pool mid |
| tokens[].impactPercent | what a thousand unit order would cost against that mid |
| tokens[].hops | 1 for a direct pool, 2 through USDC |
| reference | always pool-mid |
GET /api/quote
A price for an exact amount. side=buy spends USDC, side=sell spends the asset.
curl "https://app.usespecie.xyz/api/quote?token=EURC&amount=100&side=buy"POST /api/swap
The same quote, plus the calldata to sign and a simulation of it from your address. Nothing is signed here: the answer is a transaction you may choose to send.
curl -X POST https://app.usespecie.xyz/api/swap \
-H "content-type: application/json" \
-d '{
"token": "EURC",
"side": "buy",
"amount": "100",
"address": "0xYourAddress",
"slippageBps": 50
}'What comes back
| Field | Meaning |
|---|---|
| routable | false when no pool with liquidity exists, with reason |
| safe | false when the fill lands more than 3% under the pool mid; no calldata is returned |
| amountOut | what the pool returns before the fee |
| lossPercent | price impact against midRate, the pool priced at one unit |
| feeBps | the Specie fee in basis points, taken from the output |
| minimums.gross | minimum the pool must return, enforced on the swap |
| minimums.net | minimum that must reach your wallet after the fee |
| pool | the winning route: fee tier and pool id, or the hops and legs |
| approvals[] | ERC-20 and Permit2 steps to send first, each with to and data |
| tx | the swap transaction: to, value, data |
| preflight.ok | the simulation passed; the interface arms only on true |
| preflight.willReceive | what the simulation says lands in your wallet |
| preflight.feeTaken | what the simulation says the fee takes |
| preflight.gasUsed | gas the simulated transaction used |
| preflight.degraded | true when the simulator was unavailable and a lighter check ran instead; willReceive and feeTaken are then absent |
| preflight.check | which lighter check ran: gas-estimate or approvals-only |
| preflight.note | a plain sentence describing that check |
| quotedAt | when this answer was built, in milliseconds |
Status codes
| Code | When |
|---|---|
| 200 | answered, including the honest refusals: routable: false and safe: false |
| 400 | unknown asset, missing address, or an amount that is not a positive number |
| 502 | the chain could not be read |
| 503 | Uniswap is not deployed at the configured addresses; the error names what is missing |
A 503 means the deployment could not find Uniswap where it expected, for instance when it points at a network without it. The swap panel turns that into a plain message that swaps are unavailable, instead of drawing an empty market.
Sending a swap yourself
- Post to
/api/swapand checkpreflight.okis true. - Send every entry in
approvalsin order, waiting for each. - Send
tx. - Re-post before signing if more than a few seconds passed. A quote and its simulation are statements about one block.