Response Signatures
0x can sign API responses with RFC 9421 HTTP Message Signatures using Ed25519. A valid signature proves that a response came from 0x and that it answers the exact request you sent, so a quote cannot be altered in transit or reused for a different order.
Signing is useful when the component that acts on a quote cannot trust the network path to 0x, for example a secure enclave that checks calldata against a user’s intent before signing a transaction.
See the signed responses example for a complete TypeScript implementation that requests and verifies signed EVM quotes and Solana swap instructions.
Supported Endpoints
- Swap API:
/swap/allowance-holder/price,/swap/allowance-holder/quote,/swap/permit2/price,/swap/permit2/quote - Gasless API:
/gasless/price,/gasless/quote,/gasless/submit,/gasless/status - Solana Swap API:
/solana/swap-instructions
Requesting a Signed Response
Signing is opt-in per request. Add an Accept-Signature header with any value:
The response carries three extra headers:
Requests without Accept-Signature are unchanged.
What the Signature Covers
The signature parameters are created, keyid, alg="ed25519" and tag="0x-swap-api". The signature label is sig.
Binding POST Requests
For POST requests the order is in the request body, which the query string does not cover. Send a Content-Digest header with the sha-256 of your request body, and the signature covers it too:
0x checks the header against the body before signing. The request is rejected with 400 if:
- the
Content-Digestdoes not match the body, - the
Content-Digesthas nosha-256member, - or the body is larger than 1 MB.
The 400 response has a JSON body with a message:
Always send Content-Digest on POST requests you want signed, such as Solana swap instructions. Without it, the signature does not bind the response to your order.
Verifying a Response
Reject the response if any of these checks fails:
Check the key and algorithm
Parse Signature-Input and look up the keyid in the public keys you trust. Reject unknown key ids, and reject any alg other than ed25519.
Check coverage
Read the covered components from Signature-Input rather than assuming a fixed list. Require at least @status, content-digest, @method;req, @authority;req, @path;req and @query;req, plus content-digest;req for POST requests.
Check the digests
Compute the sha-256 of the response body and compare it with the response’s Content-Digest. For POST requests, also compare your request body with the Content-Digest you sent.
Verify the signature
Rebuild the signature base as described in RFC 9421 section 2.5, using the values from your request and the response. Verify the Signature over it with the Ed25519 public key.
For a complete, dependency-free TypeScript implementation, see the signed responses example.
A signature binds a response to the request’s parameters, not to a single request. The same signed response could be returned again for an identical request. The freshness check limits that to responses at most 60 seconds old.
Public Keys
Key Rotation
Signing keys are rotated. This page always lists the current keys.
- Select the verification key by the signature’s
keyid, never by position. - Before a rotation, the new key is published here next to the current one. Add it to your trusted keys before it becomes active.
- A retired key is removed from this page. Stop trusting it once it is removed.
Not Signed
- Responses rejected before reaching the API, such as invalid API keys, missing permissions or rate limits.
- Streaming endpoints.