NEAR Intents: WebSocket Reference
Subscribe and respond to quote requests in real-time
NEAR Intents exposes a WebSocket endpoint for market makers (solvers) to receive and respond to quote requests in real-time.
Endpoint: wss://solver-relay-v2.chaindefuser.com/ws
Authentication
This endpoint requires a Partner JWT, sent as an Authorization: Bearer header on the WebSocket handshake request (not X-API-Key, that header is only for the REST RPC endpoint):
Authorization: Bearer <your_partner_jwt>
To obtain a Partner JWT, register through the Partner Portal.
subscribe
Subscribe to quote requests or quote status events.
params[0] string required
Subscription name: "quote" or "quote_status"
params[1] object
Optional quote filters. Second positional param. Omit, null, or {} = no filter. Set fields are ANDed; empty array on a field = no restriction for that field.
Put the defuse_asset_identifier values for the tokens you support in tokens_in and tokens_out (same IDs as on quote events).
| Field | Type | Keep the quote if |
|---|---|---|
tokens_in |
string[] |
input token (defuse_asset_identifier_in) is in this list |
tokens_out |
string[] |
output token (defuse_asset_identifier_out) is in this list |
Also optional: params[2] guaranteed (see Guaranteed Delivery).
[!NOTE]
For
"quote_status"with guaranteed delivery, leave filters empty (nullor{}).
Example request
Native NEAR pair:
{ "jsonrpc": "2.0", "id": 1, "method": "subscribe", "params": [ "quote", { "tokens_in": ["nep141:usdt.tether-token.near", "nep141:wrap.near"], "tokens_out": ["nep141:usdt.tether-token.near", "nep141:wrap.near"] } ] }Cross-chain assets (still
nep141:IDs on the bus):{ "jsonrpc": "2.0", "id": 1, "method": "subscribe", "params": [ "quote", { "tokens_in": [ "nep141:eth-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.omft.near", "nep141:eth-0xdac17f958d2ee523a2206206994597c13d831ec7.omft.near" ], "tokens_out": [ "nep141:eth-0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48.omft.near", "nep141:eth-0xdac17f958d2ee523a2206206994597c13d831ec7.omft.near" ] } ] }
Example response
{ "jsonrpc": "2.0", "id": 1, "result": "00000000-0000-0000-0000-000000000000" }Response fields:
result- Subscription ID used for receiving events and unsubscribing
quote events
After subscribing to "quote", you'll receive events like this:
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"subscription": "00000000-0000-0000-0000-000000000000",
"quote_id": "00000000-0000-0000-0000-000000000000",
"defuse_asset_identifier_in": "nep141:ft1.near",
"defuse_asset_identifier_out": "nep141:ft2.near",
"exact_amount_in": "1000",
"min_deadline_ms": 60000,
"min_wait_ms": 1900,
"max_wait_ms": 3000,
"protocol_fee_included": false
}
}
[!NOTE]
Only one of
exact_amount_inorexact_amount_outwill be specified in each request.
Event fields:
quote_id— Identifier for this auction; include it in yourquote_responsedefuse_asset_identifier_in/defuse_asset_identifier_out— Token pairexact_amount_inorexact_amount_out— Fixed side of the trademin_deadline_ms— Minimum validity time your signed offer should supportmin_wait_ms/max_wait_ms— Auction collection window (see Auction timing)protocol_fee_included— Whentrue, this is typically a router sub-leg auction with a shorter accept window
Auction timing (min_wait_ms / max_wait_ms)
Each quote request opens a short auction on the relay. You do not set these fields when responding — they are chosen by the quote requester (or by the router for multi-hop sub-legs) and appear on the inbound event.
| Field | Meaning |
|---|---|
min_wait_ms |
Mandatory collection window. The relay will not close the auction early before this elapses. |
max_wait_ms |
Hard deadline. The auction always ends by then, even if no early close happened. |
Timeline
- The auction starts when the relay publishes the quote request.
- From
0 → min_wait_ms, the relay collects responses and does not settle early. - After
min_wait_ms, if any responses have arrived, the relay may close after a short grace period. - At
max_wait_ms, the auction always closes. - Once closed, the quote is removed. Late
quote_responsecalls fail withquote not found or already finished.
Effective windows solvers see
| Request kind | How to recognize it | Effective collect window |
|---|---|---|
| Top-level auction | protocol_fee_included absent or false |
min_wait_ms is floored to at least 300ms, then up to ~300ms grace if results exist |
| Router sub-leg | protocol_fee_included: true (often partner_id: router-solver) |
No 300ms floor. Grace is ~50ms. FastQuote legs often use min_wait_ms: 1, so the accept window is roughly ~51ms total |
max_wait_ms is still the upper bound in both cases. When responses arrive quickly, the auction often ends around min_wait_ms + grace, not only at max_wait_ms.
[!WARNING]
Router FastQuote legs (
protocol_fee_included: true,min_wait_ms: 1) require end-to-end response latency well under ~50ms. A ~50ms WebSocket round trip is enough to miss the window even if your handler itself finishes in under 1ms.
quote_status events
After subscribing to "quote_status", you'll receive settlement notifications:
{
"jsonrpc": "2.0",
"method": "subscribe",
"params": {
"quote_hash": "00000000000000000000000000000000",
"intent_hash": "00000000000000000000000000000000",
"tx_hash": "8yFNEk7GmRcM3NMJihwCKXt8ZANLpL2koVFWWH1MEEj"
}
}
[!NOTE]
quote_statusevents published while your connection is down are lost by default. To recover missed events after a disconnect, opt into Guaranteed Delivery.
quote_response
Respond to a quote request with a signed intent. A unique id is required in the JSON-RPC message.
[!NOTE]
signed_datais produced by signing yourtoken_diffintent with the NEAR key you registered on the Verifier contract, it's not something you construct by hand. See the Example Solver for the real signing code, and publish_intent for the exactsigned_datashape.
quote_id string required
Quote request identifier from the event
quote_output object required
amount_out- Proposed amount forexact_amount_inrequestsamount_in- Proposed amount forexact_amount_outrequests
signed_data object required
Signed intent data (same format as publish_intent)
other_quote_hashes string[]
Optional hashes of other quotes needed to fulfill this intent
Example request
{ "jsonrpc": "2.0", "id": 1, "method": "quote_response", "params": [ { "quote_id": "00000000-0000-0000-0000-000000000000", "quote_output": { "amount_out": "300" }, "signed_data": { "standard": "nep413", "payload": { "recipient": "intents.near", "nonce": "Vij2xgAlKBKzAEiS6N1S/hcQLaHzX2s1fNKhBDblXT4=", "message": "{\"deadline\":\"2024-10-14T12:53:40.000Z\",\"intents\":[{\"intent\":\"token_diff\",\"diff\":{\"nep141:ft2.near\":\"-300\",\"nep141:ft1.near\":\"500\"}}],\"signer_id\":\"solver.near\"}" }, "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2", "signature": "ed25519:WQXG37prMyT4f1vp6JSvamsjqDR5fSnDiinSPaCoq9sPcDgFGPRiMWX7csqqudDbzc8i6wrfpemgpVX2wQDmwww" } } ] }
Example response
{ "jsonrpc": "2.0", "id": 1, "result": "OK" }Response fields:
result-"OK"when the quote response is accepted
unsubscribe
Unsubscribe from a subscription.
params[0] string required
Subscription ID returned by subscribe
Example request
{ "jsonrpc": "2.0", "id": 1, "method": "unsubscribe", "params": ["00000000-0000-0000-0000-000000000000"] }
Example response
{ "jsonrpc": "2.0", "id": 1, "result": "OK" }Response fields:
result-"OK"when unsubscribed successfully