The examples use the pre-production REST API at
https://api.qfex.io and Trade WebSocket at wss://trade.qfex.io. Use the environment URLs and credentials supplied by QFEX for your integration.
This flow returns API keys. Wallet session authentication returns access and refresh tokens; OAuth uses an application authorization grant.
Before you start
Your builder needs:- A QFEX account with an active builder code.
- A username on that account, used in the generated key’s label.
- An existing API public key and secret owned by the builder-code account.
- The
register_userpermission enabled on that builder API key. Contact support@qfex.com to enable it;subaccount_opsdoes not grant registration access.
1. Fetch the wallet message
Pass the user’s Ethereum address and your builder-code UUID:200 OK response contains a message string. For example:
message returned by the endpoint, unchanged. The domain and URI are configured by QFEX for the environment; do not replace them with your application’s URL.
The endpoint generates a fresh nonce and a ten-minute validity window. Fetch a new message if signing or submission takes too long. Returning a message does not establish that a builder exists or is active; those checks happen during registration.
2. Ask the wallet to sign
Use the EIP-1193 provider selected by the user. Rabby supports this interface. When multiple wallets are installed, use EIP-6963 discovery rather than assumingwindow.ethereum is the selected wallet.
{ message, signature } to your backend. Do not add the words Wallet signature or the signature itself to the message string.
3. Register the user and create the trading key
Your backend callsPOST /builder/web3/api-key using the builder’s credentials and four HMAC headers:
The HTTP nonce is separate from the nonce inside the wallet message. Generate new HMAC headers for each request or retry.
Example for a Node.js backend:
message and signature. QFEX resolves the builder code from the authenticated builder account and requires the signed message to authorize that exact code. Use the builder’s own API key for this request, rather than an end user’s trading key.
The wallet signature must match the address in the message. The message must have been issued within ten minutes, must not be expired or issued in the future, and must use a domain and URI accepted by QFEX Auth.
A previously unseen wallet creates a QFEX user and main account through wallet signup. An existing wallet resumes its existing user. Account creation must complete before the key can be issued.
Response and key permissions
Successful creation returns201 Created with Cache-Control: no-store:
The key grants order execution and read access to orders, positions, and balances on the main account. Withdrawals are disabled. Subaccounts are outside its scope. Access and refresh tokens are not returned by this endpoint.
Store the response credentials securely and avoid logging or caching them. They authenticate subsequent trading requests as the wallet user; they do not replace the builder’s registration credentials.
Replacement and trading attribution
The key is labelledbuilder- followed by the builder account’s username, for example builder-alice. Issuing another key for the same user and builder label deletes the previous key and its stored secret. A failed key replacement rolls back and preserves the previous key. Keys for other users and other builder labels remain unaffected.
There is no automatic revocation immediately after use. A successful replacement invalidates the previous key for subsequent authentication. Keys whose labels start with builder- or managed are excluded from the user’s normal API-key listing.
Use the returned user key with HMAC Trade WebSocket authentication, and include your builder-code UUID in params.builder_code. The key label alone does not attribute orders to the builder. Attach the code again whenever you reconnect.
Errors
For direct browser calls, the API must allow your origin and request headers through CORS. The backend handles the underlying Auth exchange; this builder flow does not require your frontend to call
/auth/v1/token?grant_type=web3 or hold an Auth client key.