Skip to main content
GET
/
streaming-quotes
Stream quotes (SSE)
curl --request GET \
  --url https://api.leokit.dev/streaming-quotes \
  --header 'Api-Key: <api-key>'
"data: {\"type\":\"init\",\"quote_id\":\"019b4c6e-d6c2-7000-b851-48a863f2f4b7\",\"timestamp\":\"2025-12-23T18:18:14.213Z\",\"total\":5}\n\ndata: {\"type\":\"quote\",\"protocol\":\"thorchain\",\"data\":{...}}\n\ndata: {\"type\":\"final\",\"quotes\":[...],\"timestamp\":\"...\",\"quote_id\":\"...\"}\n\ndata: {\"type\":\"finished\"}\n\n"

Documentation Index

Fetch the complete documentation index at: https://docs.leokit.dev/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The streaming-quotes endpoint emits Server-Sent Events as each protocol returns a quote, instead of waiting for all protocols to complete. Use this for snappy UI — display the first quote in ~200ms instead of waiting 5+ seconds for the slowest aggregator. For a hands-on walkthrough see the Streaming Quotes guide.

Endpoint

GET /leokit/streaming-quotes

Request

Authentication

EventSource cannot set custom headers reliably, so authentication accepts both styles:
MethodExample
Api-Key headerApi-Key: YOUR_API_KEY (preferred when possible)
api_key query parameter?api_key=YOUR_API_KEY

Query Parameters

ParameterTypeRequiredDescription
from_assetstringYesSource asset in CHAIN.SYMBOL-ADDRESS format
to_assetstringYesDestination asset in CHAIN.SYMBOL-ADDRESS format
amountstringYesAmount in source-asset base units (wei, sats, etc.)
originstringNoSource wallet address (improves quote accuracy)
destinationstringNoDestination wallet address
streaming_intervalnumberNoTHORChain/MAYAChain streaming interval (default 1)
streaming_quantitynumberNoTHORChain/MAYAChain streaming sub-swap count
api_keystringNoAlternative to Api-Key header (see above)

Response

Headers

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

Event Sequence

Events are sent as data: <json>\n\n chunks (legacy SSE format — no named event: fields).
OrderEvent payload typeDescription
1initStream opened, includes quote_id and total protocols being queried
2..NquoteOne per protocol that returns a valid quote
N+1finalAggregated, sorted, deduplicated payload (after all settle)
N+2finishedStream closing
If no protocols return a usable quote, an error event is sent in place of final.

Event Payloads

{
  "type": "init",
  "quote_id": "01953c9a-...",
  "timestamp": "2026-04-28T12:00:00.000Z",
  "total": 7
}

Quote Object Fields (in final event)

FieldDescription
expectedAmountOutNumNumeric expected output (for sorting)
totalFeesUsdTotal combined fees in USD
totalSwapSecondsEstimated time-to-settle
flagsTags like FASTEST, CHEAPEST, BEST_OUTPUT

Timeouts

  • Total budget: 8 seconds. Protocols that haven’t responded by then are dropped.
  • Per-protocol circuit breaker: 5 seconds. Protocols that fail repeatedly are skipped.

Examples

Browser (EventSource)

const url = new URL("https://api.leokit.dev/leokit/streaming-quotes");
url.searchParams.set("from_asset", "ETH.ETH");
url.searchParams.set("to_asset", "BTC.BTC");
url.searchParams.set("amount", "1000000000000000000");
url.searchParams.set("api_key", "YOUR_API_KEY");

const es = new EventSource(url.toString());

es.onmessage = (e) => {
  const event = JSON.parse(e.data);
  switch (event.type) {
    case "init":     console.log("started", event.quote_id); break;
    case "quote":    console.log("got", event.protocol);     break;
    case "final":    console.log("done", event.quotes.length); break;
    case "finished": es.close(); break;
    case "error":    console.error(event); es.close(); break;
  }
};

Server (fetch)

const res = await fetch(
  "https://api.leokit.dev/leokit/streaming-quotes?from_asset=ETH.ETH&to_asset=BTC.BTC&amount=1000000000000000000",
  { headers: { "Api-Key": "YOUR_API_KEY" } }
);

const reader = res.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { value, done } = await reader.read();
  if (done) break;
  const chunk = decoder.decode(value);
  for (const line of chunk.split("\n\n")) {
    if (!line.startsWith("data: ")) continue;
    const event = JSON.parse(line.slice(6));
    // handle event
  }
}

Errors

StatusCodeDescription
400BAD_REQUESTMissing or malformed from_asset, to_asset, or amount
400INVALID_ASSET_FORMATAsset string not in CHAIN.SYMBOL-ADDRESS format
401INVALID_API_KEYMissing or invalid API key
The UNABLE_TO_RETRIEVE_QUOTES error is delivered inside the SSE stream as a type: "error" event, not as an HTTP error. See the error codes catalog for the full list.

Authorizations

Api-Key
string
header
required

Demo API-Key (Sandbox): 7037d2b3-9c76-4f62-b730-c544f7570fa4

Query Parameters

from_asset
string
required

Input asset identifier.

to_asset
string
required

Output asset identifier.

origin
string
required

From wallet address.

destination
string
required

To wallet address.

amount
string
required

Amount to swap.

api_key
string

Alternative to Api-Key header (useful for EventSource which cannot set headers).

Response

Server-Sent Events stream. Events are sent as data: {json}\n\n format.

SSE stream with events: init, quote (per protocol), final (sorted), finished.