Six calls are a working exchange. List the assets, stream the offers from every connected provider, validate the address, open the order, poll it, show the result — all under your own brand, and non-custodial throughout: the user's coins go to the provider, never to SwapZilla and never to you.
- One quote request fans out to every enabled exchange in parallel.
- Server-sent events deliver the first offer in 200–400 ms.
- Private swaps — routed through Monero — are two extra endpoints, not a different integration.
- There is no package to install: the surface is small enough to be your own client.
The six calls
| Call | What it is for | Key |
|---|---|---|
GET /v1/assets | The currency selector: every asset and network with a provider behind it. | no |
GET /v1/providers | Exchange names and whether they are enabled — for your "powered by" row. | no |
GET /v1/validate-address | Address format check before the user can submit. known:false means unverified, not valid. | no |
GET /v1/partner/quotes-sse | Live offers, streamed as each provider answers. | yes |
POST /v1/partner/orders | Turns the chosen offer into a deposit address. | yes |
GET /v1/partner/orders/{id} | Status to settlement: DONE carries AmountToReceived and TxID. | yes |
Two more when you want them: /v1/partner/private-quotes and
/v1/partner/private-orders route a swap through an intermediate
anonymous asset in two chained legs, and
/v1/export/rates.xml publishes the best cross-provider rate per
direction as a BestChange-style feed.
A client, in about thirty lines
There is no SDK package to install — and the surface does not need one. This is the whole thing:
const BASE = "https://api.swapzilla.io";
export class SwapZilla {
constructor(private key: string) {}
private headers() { return { "X-API-Key": this.key, "Content-Type": "application/json" }; }
assets() {
return fetch(`${BASE}/v1/assets`).then((r) => r.json());
}
quotes(q: Record<string, string>) {
return fetch(`${BASE}/v1/partner/quotes?${new URLSearchParams(q)}`, {
headers: this.headers(),
}).then((r) => r.json());
}
createOrder(body: object, idempotencyKey: string) {
return fetch(`${BASE}/v1/partner/orders`, {
method: "POST",
headers: { ...this.headers(), "Idempotency-Key": idempotencyKey },
body: JSON.stringify(body),
}).then((r) => r.json());
}
order(id: string) {
return fetch(`${BASE}/v1/partner/orders/${id}`, { headers: this.headers() })
.then((r) => r.json());
}
}
The streaming endpoint is the one worth a little more code, because it is what makes the UI feel instant:
const res = await fetch(sseURL, {
headers: { "X-API-Key": key, Accept: "text/event-stream" },
});
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
// split on "\n\n", read the "event:" / "data:" lines, and render each `offer`
// as it lands. `done` ends the stream and carries the final `deviations` map —
// re-rank the offers you already drew instead of waiting to draw them.
Shipping it as a widget
A widget lives in someone else's page, which is exactly where an API key must never be. The layout that works:
- Proxy every keyed call. The API answers with
Access-Control-Allow-Origin: *, so a browser can call it — and then the key is one DevTools tab away from anyone. - Pass the stream through. Your proxy can forward
text/event-streamuntouched; the widget keeps its live prices without ever seeing the key. - Cache quotes for 5–10 seconds. There is no rate limit on our side, but providers throttle repeated quoting long before your users notice.
- Show what the user is choosing between. Each offer carries
ProviderName,EstimatedMins,KycRating(A to D) andDeviationPercent— the cheapest offer is not always the one they want. - Validate the destination address with
/v1/validate-addressbefore the submit button lights up. It is a keyless call, so the widget can make it directly.
What you build, and what you get
| SwapZilla gives you | You build |
|---|---|
| Offers from every connected exchange, ranked, in one request | The interface they are rendered in |
| Order creation, deposit addresses and status to settlement | The proxy that holds the key |
| Asset, network and provider lists that stay current | Your own caching, at 5–10 seconds |
| Idempotency, refund addresses, slippage guards | Storage of your client_order_id mapping |
A support reference (ProviderOrderID) per order | First-line support for your own users |
Not on offer, so that nobody plans around it: there is no published SDK
package, no hosted widget bundle, no webhooks, and no production sandbox — for
deterministic smoke tests we can enable a mock provider on your
key instead.
Who integrates it
- Wallets adding swap without adding custody, liquidity or a licence conversation.
- Telegram bots and mini apps, where the whole exchange is four screens and the key sits safely on the bot's server.
- Aggregators and monitors, which can also read
/v1/export/rates.xmldirectly. - Portfolio trackers and dashboards turning "you are overweight in ETH" into a swap the user can accept in place.
Questions
Is there an official SwapZilla SDK?
Not as a published package. The partner API is plain JSON over HTTP with one header, and a complete client fits in about thirty lines in any language — the reference at /developers/ documents every endpoint, field and status so you can write that client directly. The closest thing to a worked example is the open-source swapzilla-mcp server: a small JavaScript client with six operations, MIT-licensed and readable in one sitting.
Can the widget call the API from the browser?
Technically yes — the API sends Access-Control-Allow-Origin: * — but never with your key. A key is a bearer credential: whoever holds it trades as you. Proxy keyed calls through your own backend and add the header there. The keyless endpoints (/v1/assets, /v1/providers, /v1/validate-address) are fine to call directly.
How fast are quotes?
Over /v1/partner/quotes-sse the first offer usually lands in 200–400 ms, and the stream ends by itself at timeout_ms, which defaults to and is capped at 5000 ms. The non-streaming /quotes waits for the slowest provider that still answers within the window.
Are there rate limits?
None on SwapZilla's side. Providers do throttle repeated quote requests, so cache quotes for 5–10 seconds, poll orders no faster than every 5 seconds, and call the synchronous refresh endpoint at most once every five seconds.
Can I white-label the exchange completely?
Yes. Nothing in the flow requires SwapZilla's interface or branding: you render the offers, the deposit screen and the status timeline yourself. Every call made with your key is tagged with your partner id, and you only ever see your own orders.
What is the deal with private swaps?
A private swap breaks the on-chain link between sender and receiver by routing through an anonymous intermediate asset — Monero by default — as two chained orders under one PrivateSwapID. Routes that would use the same provider for both legs are discarded. The address to show the user is FirstOrder.DepositAddress.
What else the same key builds
- Crypto payment links and invoicesPay-by-link and invoicing for freelancers and contractors — quote by the amount due, settle straight to the payee's wallet.
- Crypto payment processing and acquiringCheckout for shops and SaaS: accept 100+ assets, settle in one, reconcile by your own order id.
- Crypto payroll for contractors and remote teamsRecurring payouts to a contractor roster: each person's own asset and network, exact net amounts, per-run reconciliation.
- Multi-send: batch payouts to many addressesOne-off fan-out to hundreds of addresses: cross-chain, per-recipient status, safe retries.
- Your own MCP server for AI agentsThe published swapzilla-mcp server in one line — or your own, on your partner key, with allow-lists and spending caps.
- Streaming quotes, live rates and price alertsServer-sent quote streaming, an always-fresh rate feed and order tracking you can turn into alerts.
Getting a key
Register in the partner cabinet and your partner id and the api_key that goes in X-API-Key are issued at once. The key starts working once it is activated: write to @swapzilla_support_bot with a sentence about what you are building. Every endpoint, field and status is in the partner API reference.