fill() mints option tokens atomically and pulls collateral in the same transaction. All you need ready is USDC and two one-time USDC approvals.
The Three-Channel Transport
Maker integration uses a three-channel split. Each channel does one job:You must keep both the SSE quote-request stream (channel 1) and the post-trade WebSocket (channel 3) open at the same time: the SSE stream tells you what to quote, and the WebSocket tells you when you won. Quotes and confirmation signatures go out over REST (channel 2).
X-API-Key header (or ?apiKey=); the WebSocket uses ?apiKey= on the URL or an auth message.
What You Need
1
An API key
A per-MM API key generated from the Convallax dashboard (Settings → API Keys). The key maps to your stable
makerId and works immediately. See the Authentication guide.2
Your own wallet + key
You quote with your own wallet address (it becomes
Order.maker) and sign settlement orders with that wallet’s private key. The backend never holds it.3
USDC + two approvals
Settlement is atomic mint-on-fill — there is no inventory to pre-mint and no ERC-1155 approvals. You only need USDC and two one-time USDC approvals, depending on which side of the trade you take:
- Posting collateral (you become the writer):
usdc.approve(coreAddress, collateral). When a fill executes,ConvallaxCorepulls your collateral and mints fresh option tokens to the holder. - Paying premium (you are buying the option from the taker):
usdc.approve(settlementAddress, premium).
makerSelling = true), you post collateral → approve Core. For a short fill (the taker writes, makerSelling = false), you pay premium → approve Settlement.How It Works
1
Subscribe to the quote-request stream (SSE)
Open an SSE connection to the maker stream with your API key in the Each
X-API-Key header. On connect you receive a connected event, then a snapshot of currently open requests, then live quote_request events.quote_request carries the trade parameters and an SSE id: for reconnect/replay. See the Quote Request Stream guide for the full event list and Last-Event-ID semantics.2
Connect the post-trade WebSocket
In parallel, open the post-trade WebSocket so you learn the moment one of your quotes wins. On auth you receive a
connected message with protocolVersion: 3.3
Submit your quote (REST)
For each The response returns a server-generated Store that
quote_request, compute your price and POST /v1/mm/quotes. The quote.maker field must be your own wallet address — it becomes Order.maker and you must be able to sign for it.quoteId that is stable across updates for the same maker + request:quoteId keyed by requestId — you will need it to confirm if you win. You can update your quote at any time while the request is open by re-POSTing for the same requestId; only your latest quote is kept.4
Win, sign, and confirm (WebSocket → REST)
When the trader commits and your quote wins, the post-trade WebSocket pushes a Sign the The backend verifies that your signature recovers to
quote:accepted message containing the exact Order, the EIP-712 domain/types, and a confirmationDeadline:order with your own wallet key and POST the signature to the confirm endpoint before the deadline:order.maker, then pushes quote:confirmed to you (and quote:rejected to other makers).5
Settle
Once you confirm, the taker receives your signed order and calls
fill() on ConvallaxRFQSettlement. In a single atomic transaction, fill() calls ConvallaxCore.mintFor(...) to pull collateral from the writer, mint fresh option tokens to the holder, and move the premium — all or nothing. For a long fill you post collateral and the option is minted to the taker; for a short fill the taker posts collateral and the option is minted to you.6
Reclaim collateral after settlement
On a long fill you are the writer — your USDC collateral stays locked in You receive
ConvallaxCore until the series expires and is settled. Once the series is settled (see the Settlement guide), reclaim your share of the leftover collateral with a single call:writerCollateral × writerPoolRemaining / totalCollateral — your original collateral minus whatever was paid out to holders. This is a one-shot call per series (your recorded collateral is zeroed after). Poll GET /v1/series with settled=true to find expired series you wrote, then claim. See claimWriterCollateral() for details.Confirmation Deadline & Fallback
When a taker commits, the winning maker has a limited window (MAKER_CONFIRMATION_MS, default 10 seconds) to sign and POST the signature:
- You confirm in time → the taker settles against your signed order; you receive
quote:confirmed. - You miss the deadline → the backend falls back to the next-best maker’s quote and asks them to confirm; you receive
quote:rejected. - No maker confirms → the request stays open and the taker can retry.
Core Quoting Loop
Winner Selection
Quote Validation Rules
Your quote must pass these validation checks:Buy vs sell sizing. On a buy the taker submits a USDC budget (
trade.budgetUsd), not a contract count. You quote a per-option price and a size = the most whole options you’re willing to write at that price. The taker receives floor(budgetUsd / price) options, capped by your size (a partial fill if your size is smaller). On a sell the taker submits a contract count (trade.size) and you quote the size you’ll take. Either way, price is always per one option.The Order You Sign (EIP-712)
Check Relay Status
Verify connectivity and see how many makers are online:makersConnected counts makers subscribed to the SSE quote-request stream; socketsConnected counts live post-trade WebSocket sockets. See the Relay Status reference.
Environment Variables
If you are running your own relay instance, these variables control auth and quote request behavior:
If no maker keys are configured, the relay runs in OPEN dev mode (anonymous makerId, accepts anyone) — see the Authentication guide.
Dependencies (Node.js bots)
Market-maker bots run in Node.js, not in a browser. Install these packages before running the example below:If your SSE client cannot set headers at all, you can pass the key on the URL instead:
GET .../quote-requests/stream?apiKey=<your-key>. The npm eventsource package with headers: { 'X-API-Key': ... } is still the recommended approach.Complete Worked Example Bot
A minimal bot that subscribes to the SSE stream, submits quotes via REST, listens on the WebSocket for wins, and signs winning orders withethers:
Before going live, set your USDC approvals —
usdc.approve(coreAddress, ...) if you’ll post collateral, and usdc.approve(settlementAddress, ...) if you’ll pay premium — so settlement succeeds the instant a taker fills your signed order. No inventory minting or ERC-1155 approvals are needed.