https://rfq.kairos.trade.
Authentication
Two credential forms are accepted. API credentials use all three headers together:RS256, issuer kairos.trade, audience
kairos-api, with sid and ver: 1 claims and a required exp.
Every JWT is checked for revocation on connect and, on the WebSocket, again
every 30 seconds. Authentication fails closed with
503 auth_dependency_unavailable when revocation status cannot be verified.
API-credential principals carry the scopes stored on the credential, and an
ipWhitelist on the credential is enforced against the client IP.
Gotcha: an IP-allowlist miss is a
403, not a 401. A non-allowlisted
source gets 403 forbidden, which is easy to misread as a scope problem.
Check the source address before you re-issue credentials.Scopes
The scope
* satisfies every check.
Gotcha: a JWT with no
scopes claim cannot quote. It is granted
rfq:read, rfq:create, and rfq:accept — not rfq:quote. Market
makers need a credential that carries rfq:quote explicitly.Endpoint index
/v1/venues/capabilities needs authentication but no particular scope.
Rules that apply to every request
The requester flow
- Check venue capabilities.
GET /v1/venues/capabilitiestells you what each venue currently supports. Do this before selectingvenues— see Create an RFQ for what happens when a venue cannot accept requester fanout. - Create the RFQ.
POST /v1/rfqswith a freshIdempotency-Keyreturns201and anrfq_id. - Watch for quotes. Connect to
GET /v1/streamand consumequote.created/quote.revised/quote.withdrawn, or pollGET /v1/rfqs/{rfq_id}/quotes. - Accept one.
POST /v1/quotes/{quote_id}/acceptreturns202and an acceptance inpending_routing. This reserves quantity; it does not fill. - Follow the acceptance to a terminal state via
GET /v1/executions/{acceptance_id}or theacceptance.*events.executedalso emitsexecution.normalized.v1. - Cancel what you no longer want.
POST /v1/rfqs/{rfq_id}/cancelmoves the RFQ tocancelledand its live quotes towithdrawn.
The market-maker flow
- Confirm your credential carries
rfq:quote. A scopeless JWT does not. - Discover open venue RFQs with
GET /v1/exchange-rfqs, or consume the maker broadcast stream, which callers holdingrfq:quotereceive onGET /v1/stream. - Quote it.
POST /v1/quotesreturns201. - Revise or withdraw.
PUT /v1/quotes/{quote_id}requires the new revision to be exactlycurrent + 1;DELETE /v1/quotes/{quote_id}withdraws. - Watch
quote.dispositionand theacceptance.*events for the outcome.
Create an RFQ
201.
Scope: rfq:create. Requires an Idempotency-Key header.
Example
Validation
A request that breaks any of these is rejected400 invalid_request.
Decimal quantities and prices are strings.
Gotchas
Idempotency ignores the body. Keys are (principal, operation, key).
Replaying a key returns the resource the first call created and never performs
a second mutation — so a replay with a different body still returns the
original resource. Treat a key as bound to one command.
Requester fanout is not live yet. Every venue adapter currently reportsrequester_rfq: false, so each entry invenuescomes back as atargetsentry withstate: "excluded"and areason, plus amapping_warningsentry. The201is not evidence that anything reached a venue. Read/v1/venues/capabilitiesbefore relying on fanout.
List your RFQs
rfq:read.
Discover venue RFQs
rfq:quote.
Example
Response
Results are expiry ordered and include an opaquenext_cursor plus
observed_at, which reports the local projection’s last mutation time.
Errors
Lifecycle states
RFQ
Quote
Acceptance
Errors
Errors are JSON objects whose only field iserror, except where noted.
Stream recovery
rfq:read. Upgrades to a WebSocket (101).
- Connect to
/v1/stream. - Persist the
sequenceof the last event you processed. - On reconnect, pass
after=<sequence>to replay missed durable events.
sequence, event_id,
resource_id, type, occurred_at, and data. The gateway polls roughly
every 250 ms and sends at most 250 events per poll.
Gotcha: the stream is server-push only. There are no client-to-server
messages, and after is the sole subscription control — you cannot filter or
subscribe selectively once connected.
Gotcha: always process events idempotently. A reconnect can redeliver an event that was received immediately before the disconnect.
Event types
Callers holding
rfq:quote additionally receive the maker broadcast stream of
venue-originated RFQ events.
Close codes
Scope and authentication failures happen before the upgrade and surface as an
ordinary HTTP error rather than a close frame.
Machine-readable contract
The complete machine-readable contract lives in the RFQ service’sspec/openapi.yaml and spec/asyncapi.yaml files.
