curl -N https://api.totalis.trade/v1/quote-requests/1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40/stream \
-H "X-API-Key: $TOTALIS_API_KEY" \
-H "Accept: text/event-stream"
// Native EventSource cannot send an X-API-Key header, so read the SSE stream
// with fetch instead (works in browsers and Node 18+).
async function streamQuotes(id, apiKey) {
const res = await fetch(
`https://api.totalis.trade/v1/quote-requests/${id}/stream`,
{ headers: { 'X-API-Key': apiKey, Accept: 'text/event-stream' } }
);
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) return;
buffer += decoder.decode(value, { stream: true });
let sep;
while ((sep = buffer.indexOf('\n\n')) !== -1) {
const frame = buffer.slice(0, sep);
buffer = buffer.slice(sep + 2);
const event = frame.match(/^event: (.+)$/m)?.[1];
const data = frame.match(/^data: (.+)$/m)?.[1];
if (!event || !data) continue;
const payload = JSON.parse(data);
if (event === 'best_quote') {
console.log('Best quote:', payload.best_quote, 'book_seq:', payload.book_seq);
} else if (event === 'committed') {
console.log('RFQ created:', payload.rfq_id);
return; // the stream closes after a terminal event
} else if (event === 'cancelled' || event === 'expired') {
console.log('Terminal:', event);
return;
}
}
}
}
import json
import os
import requests
quote_request_id = '1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40'
url = f'https://api.totalis.trade/v1/quote-requests/{quote_request_id}/stream'
headers = {
'X-API-Key': os.environ['TOTALIS_API_KEY'],
'Accept': 'text/event-stream',
}
event_type = None
with requests.get(url, headers=headers, stream=True) as resp:
for line in resp.iter_lines(decode_unicode=True):
if line.startswith('event: '):
event_type = line[7:]
elif line.startswith('data: '):
payload = json.loads(line[6:])
if event_type == 'best_quote':
print('Best quote:', payload['best_quote'])
elif event_type in ('committed', 'cancelled', 'expired'):
print(f'Terminal: {event_type}', payload)
break
event_type = None
event: best_quote
data: {"book_seq":1,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"b2c3d4e5-6789-0abc-def1-234567890abc","payout_odds":4.0,"user_cost":24.75,"total_payout":99,"mm_cost":74.25,"valid_until":"2026-06-01T18:45:45.000Z","market_maker_id":"did:privy:cm3mm..."}}
event: best_quote
data: {"book_seq":2,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"e5f6a7b8-9012-cdef-3456-7890abcdef12","payout_odds":4.4,"user_cost":24.75,"total_payout":108.9,"mm_cost":84.15,"valid_until":"2026-06-01T18:45:50.000Z","market_maker_id":"did:privy:cm9mm..."}}
event: status
data: {"status":"committed","committed_rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}
event: committed
data: {"quote_request_id":"1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40","rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}
Quote service
Stream quote updates
Subscribe to real-time best-quote updates for a quote request via Server-Sent Events.
GET
/
v1
/
quote-requests
/
{id}
/
stream
curl -N https://api.totalis.trade/v1/quote-requests/1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40/stream \
-H "X-API-Key: $TOTALIS_API_KEY" \
-H "Accept: text/event-stream"
// Native EventSource cannot send an X-API-Key header, so read the SSE stream
// with fetch instead (works in browsers and Node 18+).
async function streamQuotes(id, apiKey) {
const res = await fetch(
`https://api.totalis.trade/v1/quote-requests/${id}/stream`,
{ headers: { 'X-API-Key': apiKey, Accept: 'text/event-stream' } }
);
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) return;
buffer += decoder.decode(value, { stream: true });
let sep;
while ((sep = buffer.indexOf('\n\n')) !== -1) {
const frame = buffer.slice(0, sep);
buffer = buffer.slice(sep + 2);
const event = frame.match(/^event: (.+)$/m)?.[1];
const data = frame.match(/^data: (.+)$/m)?.[1];
if (!event || !data) continue;
const payload = JSON.parse(data);
if (event === 'best_quote') {
console.log('Best quote:', payload.best_quote, 'book_seq:', payload.book_seq);
} else if (event === 'committed') {
console.log('RFQ created:', payload.rfq_id);
return; // the stream closes after a terminal event
} else if (event === 'cancelled' || event === 'expired') {
console.log('Terminal:', event);
return;
}
}
}
}
import json
import os
import requests
quote_request_id = '1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40'
url = f'https://api.totalis.trade/v1/quote-requests/{quote_request_id}/stream'
headers = {
'X-API-Key': os.environ['TOTALIS_API_KEY'],
'Accept': 'text/event-stream',
}
event_type = None
with requests.get(url, headers=headers, stream=True) as resp:
for line in resp.iter_lines(decode_unicode=True):
if line.startswith('event: '):
event_type = line[7:]
elif line.startswith('data: '):
payload = json.loads(line[6:])
if event_type == 'best_quote':
print('Best quote:', payload['best_quote'])
elif event_type in ('committed', 'cancelled', 'expired'):
print(f'Terminal: {event_type}', payload)
break
event_type = None
event: best_quote
data: {"book_seq":1,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"b2c3d4e5-6789-0abc-def1-234567890abc","payout_odds":4.0,"user_cost":24.75,"total_payout":99,"mm_cost":74.25,"valid_until":"2026-06-01T18:45:45.000Z","market_maker_id":"did:privy:cm3mm..."}}
event: best_quote
data: {"book_seq":2,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"e5f6a7b8-9012-cdef-3456-7890abcdef12","payout_odds":4.4,"user_cost":24.75,"total_payout":108.9,"mm_cost":84.15,"valid_until":"2026-06-01T18:45:50.000Z","market_maker_id":"did:privy:cm9mm..."}}
event: status
data: {"status":"committed","committed_rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}
event: committed
data: {"quote_request_id":"1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40","rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}
Open a Server-Sent Events (SSE) stream for one quote request. You receive the current best quote each time market makers submit, update, or withdraw quotes.
A Privy JWT (
Sent whenever the quote book changes: a quote is submitted, updated, withdrawn, or expires.
When no quotes are active,
Sent when the quote request leaves
Immediately after
The quote request was committed into an RFQ. Follow the trade through confirmation and settlement on the WebSocket
You cancelled the quote request with Cancel.
The quote request reached its
Authentication
Send your API key in theX-API-Key header. The key needs the positions:read scope.
X-API-Key: <your-api-key>
Authorization: Bearer <jwt>) is also accepted. See Authentication.
Path parameters
string
required
The quote request ID (UUID).
SSE event types
best_quote
Sent whenever the quote book changes: a quote is submitted, updated, withdrawn, or expires. book_seq increments monotonically, so a gap means you missed an update.
{
"book_seq": 5,
"version": 3,
"request_hash": "sha256:9f86d08...",
"best_quote": {
"id": "b2c3d4e5-6789-0abc-def1-234567890abc",
"payout_odds": 4.0,
"user_cost": 24.75,
"total_payout": 99,
"mm_cost": 74.25,
"valid_until": "2026-06-01T18:45:45.000Z",
"market_maker_id": "did:privy:cm3mm..."
}
}
best_quote is null:
{
"book_seq": 6,
"version": 3,
"request_hash": "sha256:9f86d08...",
"best_quote": null
}
status
Sent when the quote request leaves active (committed, cancelled, or expired). committed_rfq_id is the created RFQ id when status is committed, and null otherwise.
{
"status": "committed",
"committed_rfq_id": "c3d4e5f6-7890-abcd-ef12-34567890abcd"
}
status, the stream sends one terminal event for the outcome (committed, cancelled, or expired) and closes. Listen for either status or the terminal event.
committed
The quote request was committed into an RFQ. Follow the trade through confirmation and settlement on the WebSocket rfq:{rfq_id} channel.
{
"quote_request_id": "1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40",
"rfq_id": "c3d4e5f6-7890-abcd-ef12-34567890abcd"
}
cancelled
You cancelled the quote request with Cancel.
{
"quote_request_id": "1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40"
}
expired
The quote request reached its expires_at without being committed.
{
"quote_request_id": "1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40"
}
Integration guide
- Open the stream after you create or update a quote request.
- On each
best_quoteevent, update the payout odds you display. Storebook_seqand the best quoteid. - To commit, send
expected_version,displayed_quote_id,displayed_quote_book_seq, andmin_payout_odds_seento Commit. - On a terminal event, close the stream and handle the outcome. On a commit, read the RFQ id from
committed_rfq_id(statusevent) orrfq_id(committedevent). Follow the trade on the WebSocketrfq:{rfq_id}channel.
Errors
| Status | Code | Description |
|---|---|---|
| 401 | UNAUTHORIZED | Missing or invalid API key. |
| 403 | FORBIDDEN | You do not own this quote request, or the credential does not start with api_ (details.reason: "wrong_api_key_type"). |
| 404 | NOT_FOUND | Quote request not found. |
curl -N https://api.totalis.trade/v1/quote-requests/1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40/stream \
-H "X-API-Key: $TOTALIS_API_KEY" \
-H "Accept: text/event-stream"
// Native EventSource cannot send an X-API-Key header, so read the SSE stream
// with fetch instead (works in browsers and Node 18+).
async function streamQuotes(id, apiKey) {
const res = await fetch(
`https://api.totalis.trade/v1/quote-requests/${id}/stream`,
{ headers: { 'X-API-Key': apiKey, Accept: 'text/event-stream' } }
);
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) return;
buffer += decoder.decode(value, { stream: true });
let sep;
while ((sep = buffer.indexOf('\n\n')) !== -1) {
const frame = buffer.slice(0, sep);
buffer = buffer.slice(sep + 2);
const event = frame.match(/^event: (.+)$/m)?.[1];
const data = frame.match(/^data: (.+)$/m)?.[1];
if (!event || !data) continue;
const payload = JSON.parse(data);
if (event === 'best_quote') {
console.log('Best quote:', payload.best_quote, 'book_seq:', payload.book_seq);
} else if (event === 'committed') {
console.log('RFQ created:', payload.rfq_id);
return; // the stream closes after a terminal event
} else if (event === 'cancelled' || event === 'expired') {
console.log('Terminal:', event);
return;
}
}
}
}
import json
import os
import requests
quote_request_id = '1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40'
url = f'https://api.totalis.trade/v1/quote-requests/{quote_request_id}/stream'
headers = {
'X-API-Key': os.environ['TOTALIS_API_KEY'],
'Accept': 'text/event-stream',
}
event_type = None
with requests.get(url, headers=headers, stream=True) as resp:
for line in resp.iter_lines(decode_unicode=True):
if line.startswith('event: '):
event_type = line[7:]
elif line.startswith('data: '):
payload = json.loads(line[6:])
if event_type == 'best_quote':
print('Best quote:', payload['best_quote'])
elif event_type in ('committed', 'cancelled', 'expired'):
print(f'Terminal: {event_type}', payload)
break
event_type = None
event: best_quote
data: {"book_seq":1,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"b2c3d4e5-6789-0abc-def1-234567890abc","payout_odds":4.0,"user_cost":24.75,"total_payout":99,"mm_cost":74.25,"valid_until":"2026-06-01T18:45:45.000Z","market_maker_id":"did:privy:cm3mm..."}}
event: best_quote
data: {"book_seq":2,"version":1,"request_hash":"sha256:9f86d08...","best_quote":{"id":"e5f6a7b8-9012-cdef-3456-7890abcdef12","payout_odds":4.4,"user_cost":24.75,"total_payout":108.9,"mm_cost":84.15,"valid_until":"2026-06-01T18:45:50.000Z","market_maker_id":"did:privy:cm9mm..."}}
event: status
data: {"status":"committed","committed_rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}
event: committed
data: {"quote_request_id":"1a6d1f06-9d4f-47cb-994b-3bdfbbef7e40","rfq_id":"c3d4e5f6-7890-abcd-ef12-34567890abcd"}
Was this page helpful?

