API, SDK & widgets

Crypto exchange API, SDK and swap widget

Six calls are an exchange: list the assets, stream the offers, validate the address, open the order, poll it, show the result. Everything renders under your brand, and the coins never leave the user's control until the provider has them.

  • Calls to integrate6
  • First offer200–400 ms over SSE
  • Providersevery enabled exchange, one query
  • Brandingyours — no SwapZilla UI required

Built on/v1/partner/quotes-sse/v1/assets/v1/providers/v1/validate-address/v1/partner/orders

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

CallWhat it is forKey
GET /v1/assetsThe currency selector: every asset and network with a provider behind it.no
GET /v1/providersExchange names and whether they are enabled — for your "powered by" row.no
GET /v1/validate-addressAddress format check before the user can submit. known:false means unverified, not valid.no
GET /v1/partner/quotes-sseLive offers, streamed as each provider answers.yes
POST /v1/partner/ordersTurns 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:

widget in the browseryour backend (adds X-API-Key)api.swapzilla.io
  • 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-stream untouched; 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) and DeviationPercent — the cheapest offer is not always the one they want.
  • Validate the destination address with /v1/validate-address before 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 youYou build
Offers from every connected exchange, ranked, in one requestThe interface they are rendered in
Order creation, deposit addresses and status to settlementThe proxy that holds the key
Asset, network and provider lists that stay currentYour own caching, at 5–10 seconds
Idempotency, refund addresses, slippage guardsStorage of your client_order_id mapping
A support reference (ProviderOrderID) per orderFirst-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.xml directly.
  • 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.

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.