CRXDocs
Get StartedLearnBuildCurateTools
  • Introduction
  • API
  • Pairs & Marks
  • Positions
  • Changelog
  • SDKs
  • Explorer
  • Using LLMs

CRX API

What is the CRX API?

The relayer's HTTP API. It brokers requests for quote, prices margin, and serves the public maker and taker registries. It is the only off-chain service a client calls to quote and bind a trade. It never takes custody — the binding happens on-chain between two firms.

What is the base URL?

The relayer base URL is read from NEXT_PUBLIC_RELAYER_URL. It is environment-specific; there is no single hard-coded host in the source.

The production relayer host is not published in this repo. Local development defaults to http://localhost:3001. All paths below are relative to that base.

How does authentication work?

Two POST calls: a challenge, then a login. The login returns a JWT valid for one hour. Some reads are public and need no token.

StepMethodPathBodyReturns
1. ChallengePOST/auth/challenge{ "address": "0x…" }{ "message": "Sign in to CRX relayer.\nAddress: …\nNonce: …\nExpires: …" }
2. LoginPOST/auth/login{ "address": "0x…", "signature": "0x…" }{ "token": "eyJ…", "expires_at": 1780313385 }
  • signature is a personal_sign over the exact message from step 1.
  • Send the token as Authorization: Bearer <token> on every authenticated call.
  • expires_at is a Unix timestamp (seconds). The token lives ~1 hour.

The trade path itself needs no session. Quoting and binding are authorized by the two EIP-712 Terms signatures, not by a JWT. Auth gates the maker's inbox and RFQ writes, not the bind.

What are the core endpoints?

The complete relayer set. auth = a Bearer token is required. write = the call changes live venue state.

MethodPathAuthWriteSummary
POST/auth/challengenonoGet the exact message your wallet must sign to log in.
POST/auth/loginnonoExchange a personal-sign signature for a 1-hour JWT.
POST/rfqyesyesOpen a directed RFQ as a taker.
GET/rfq/inboxyesnoPoll the directed RFQs waiting for your desk to price.
POST/rfq/:id/quoteyesyesPrice an RFQ (unsigned). The relayer returns canonical Terms.
POST/rfq/:id/confirmyesyesConfirm a priced RFQ with your EIP-712 signature over Terms.
GET/rfq/:id/bundleyesnoThe dual-signed bundle the taker submits on-chain to bind.
GET/marginnonoVol-scaled initial margin for a pair and notional.
GET/firm/:addrnonoA firm's general balance and open agreement count.
GET/makersnonoThe approved-maker registry.
GET/takersnonoThe approved-taker registry.
GET/healthnonoRelayer liveness.

What are the request and response shapes?

Each endpoint, with its parameters and what it returns.

POST /rfq

Open a directed request for quote. Auth required.

  • Body: { "pair": "USD/INR", "maker": "0x…", "notional": "100000", "side": "buy" }
  • pair — a currency pair label (see Pairs & Marks API, ~3 min).
  • maker — the maker address you are directing the RFQ to.
  • notional — notional in quote units, as a string.
  • side — "buy" or "sell".
  • Returns: { "id": "rfq_…", "status": "open" }.

GET /rfq/inbox

Poll the RFQs aimed at your desk. Auth required.

  • Query: maker (required) — your maker address.
  • Returns: an array of open RFQs directed at you.

POST /rfq/:id/quote

Price an RFQ. The relayer returns the canonical Terms to sign. Auth required.

  • Path: id — the RFQ id from your inbox.
  • Body: { "rate": "83.20", "valid_until": 1780313385 }.
  • valid_until — Unix timestamp; the quote expires after it.
  • Returns: { "terms": { … } } — the canonical Terms struct to sign in the next step.

POST /rfq/:id/confirm

Confirm a priced RFQ with your signature. Auth required.

  • Path: id — the RFQ id you priced.
  • Body: { "signature": "0x…" } — an EIP-712 signature over the returned Terms.
  • Returns: { "status": "confirmed" }.

GET /rfq/:id/bundle

Fetch the dual-signed bundle the taker submits on-chain to bind. Auth required.

  • Path: id — a confirmed RFQ id.
  • Returns: { "bundle": { … } }.

A bundle is not ready until the agreed quote is anchored on-chain. Anchoring takes a few seconds. A client that polls and gives up too early reads an empty bundle and wrongly concludes no maker answered.

GET /margin

Estimate the initial margin for a pair and notional. Public.

  • Query: pair (required), notional (required, quote units).
  • Returns: { "im": "4200.00" }.

GET /firm/:addr

A firm's off-chain summary. Public.

  • Path: addr — a firm wallet address.
  • Returns: { "balance": "0", "open_acas": 0 } — general balance and open master-agreement count.

GET /makers, GET /takers

The approved registries. Public.

  • No parameters.
  • Returns: an array of { "address": "0x…" }. A maker entry may carry an online flag (last poll under 30s).

GET /health

Relayer liveness. Public.

  • No parameters.
  • Returns: { "status": "ok" }.

What is the trade flow, end to end?

The order the endpoints are called in a single trade.

  1. Taker POST /rfq → { id }.
  2. Maker GET /rfq/inbox → sees the RFQ.
  3. Maker POST /rfq/:id/quote → relayer returns canonical Terms.
  4. Maker POST /rfq/:id/confirm with an EIP-712 signature over Terms.
  5. Taker GET /rfq/:id/bundle → the dual-signed bundle, once anchored.
  6. Taker submits the bundle on-chain to bind. The position is live.

The same sequence, explained: RFQ Relayer (~3 min).

Next: Pairs & Marks API (~3 min) — read supported pairs, sessions, and live marks.

PreviousTools · 2 min readIntroductionNextTools · 3 min readPairs & Marks
CRX
DocsDeskLaunch app
On-chain FX hedging. Confidential.