> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qfex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Builder Integration Guide

> Onboard QFEX users with OAuth and automatically attribute their trading to your builder code

This guide is for exchanges, DeFi aggregators, trading terminals, agents, and other applications that want to let their users trade on QFEX while earning builder rewards.

The recommended integration has two independent pieces:

1. **OAuth identifies and authorises the QFEX user.** Each end user signs in to QFEX and authorises your application. New users create their QFEX account on QFEX rather than sharing QFEX credentials with your application.
2. **Your builder code identifies your integration.** Your application attaches the same builder code to each authenticated Trade WebSocket session it opens for those users.

<Info>
  A builder code is **not assigned permanently to an end-user account**. It is
  attached to a Trade WebSocket connection. Every eligible order sent over that
  connection is attributed to the builder code for the life of the connection.
</Info>

## Integration model

A typical aggregator has:

* one QFEX account owned by the aggregator;
* one active builder code owned by that account;
* one registered QFEX OAuth client for the aggregator application; and
* one OAuth grant and token set for each QFEX user who connects their account.

You do **not** create a new builder code for every trader.

For example, if an aggregator has builder code `11111111-1111-4111-8111-111111111111`, it uses that same code when authenticating the QFEX Trade WebSocket for Alice, Bob, and every other user who trades through the aggregator. Each user still authenticates with their own QFEX OAuth access token.

## Before you start

### 1. Create your builder code

Sign in to QFEX and create a builder code in **Developer Settings → Builder code**. You can also create it with `POST /user/builder-code`.

Store the returned UUID as application configuration, for example:

```bash theme={null}
QFEX_BUILDER_CODE=11111111-1111-4111-8111-111111111111
```

The builder code is an identifier, not a user credential. Your QFEX API secrets and OAuth tokens are sensitive and must be stored separately.

See [Builder Codes API](/api-reference/builder-codes) for fee-share configuration and builder-code lifecycle operations.

### 2. Register an OAuth client

Contact [support@qfex.com](mailto:support@qfex.com) to register your integration as a QFEX OAuth client. Provide:

* your application name;
* your production redirect URI or URIs;
* a logo URL, if available; and
* whether the client is **public** or **confidential**.

Use a **confidential** client when your application has a backend that can keep a client secret. Browser-only, mobile, and desktop applications must use a **public** client and must never embed a client secret.

QFEX OAuth uses the OAuth 2.1 authorization-code flow with PKCE.

| Endpoint        | URL                                               |
| --------------- | ------------------------------------------------- |
| Authorize       | `https://verify.qfex.com/auth/v1/oauth/authorize` |
| Token           | `https://verify.qfex.com/auth/v1/oauth/token`     |
| Trade WebSocket | `wss://trade.qfex.com`                            |

<Warning>
  A QFEX OAuth access token is a user session credential and can authorise
  trading as that user. Treat access and refresh tokens as secrets. Do not log
  them, put them in analytics events, or expose a confidential client's tokens
  to the browser.
</Warning>

## End-user flow

### Step 1: User selects Connect QFEX

When the user selects **Connect QFEX** in your application:

1. Generate a high-entropy `state` value.
2. Generate a PKCE `code_verifier`.
3. Derive the SHA-256 `code_challenge` from the verifier.
4. Store `state` and `code_verifier` in the user's server-side session or another secure short-lived store.
5. Redirect the user to the QFEX authorization endpoint.

Example in Node.js:

```javascript theme={null}
import crypto from "node:crypto";

const QFEX_AUTHORIZE_URL = "https://verify.qfex.com/auth/v1/oauth/authorize";

function randomBase64Url(bytes = 32) {
  return crypto.randomBytes(bytes).toString("base64url");
}

function createPkceChallenge(verifier) {
  return crypto.createHash("sha256").update(verifier).digest("base64url");
}

const state = randomBase64Url();
const codeVerifier = randomBase64Url(48);
const codeChallenge = createPkceChallenge(codeVerifier);

// Persist these against the user's login/session until the callback completes.
session.qfexOAuth = { state, codeVerifier };

const url = new URL(QFEX_AUTHORIZE_URL);
url.searchParams.set("response_type", "code");
url.searchParams.set("client_id", process.env.QFEX_OAUTH_CLIENT_ID);
url.searchParams.set("redirect_uri", "https://aggregator.example.com/oauth/qfex/callback");
url.searchParams.set("scope", "openid email profile");
url.searchParams.set("state", state);
url.searchParams.set("code_challenge", codeChallenge);
url.searchParams.set("code_challenge_method", "S256");

response.redirect(url.toString());
```

Never omit `state` or PKCE.

### Step 2: QFEX handles sign-in or account creation

The user is sent to QFEX, not to a credential form owned by your application.

* If the user already has a QFEX account, they sign in and complete any required MFA.
* If the user does not have an account, they create one with QFEX and complete the required QFEX onboarding steps.
* The user reviews the OAuth authorisation request and approves or denies your application.

Your application should **not** collect the user's QFEX password, MFA code, API secret, or service-role credentials. It should also not create users directly through the underlying authentication provider. Keeping account creation on QFEX ensures that QFEX controls account verification, terms, eligibility, and onboarding.

<Warning>
  During the current pre-release flow, OAuth continuation through brand-new
  account signup and onboarding is still being completed. Existing QFEX users
  can complete the OAuth round-trip end-to-end. A user who creates a new QFEX
  account may need to finish onboarding, return to your application, and select
  **Connect QFEX** again. This extra step is intended to be removed before the
  builder integration is generally available.
</Warning>

### Step 3: Handle the OAuth callback

After approval, QFEX redirects to the registered `redirect_uri` with an authorization `code` and the original `state`.

```text theme={null}
https://aggregator.example.com/oauth/qfex/callback?code=...&state=...
```

On your callback endpoint:

1. Reject the request if `state` does not exactly match the value stored in the user's session.
2. Read the stored PKCE `code_verifier`.
3. Exchange the authorization code for tokens.
4. Delete the one-time `state` and `code_verifier` from the session.

### Step 4: Exchange the code for QFEX tokens

For a confidential server-side client, authenticate the client with HTTP Basic auth and send the PKCE verifier:

```bash theme={null}
curl -X POST 'https://verify.qfex.com/auth/v1/oauth/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -u "$QFEX_OAUTH_CLIENT_ID:$QFEX_OAUTH_CLIENT_SECRET" \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'code=AUTHORIZATION_CODE' \
  --data-urlencode 'redirect_uri=https://aggregator.example.com/oauth/qfex/callback' \
  --data-urlencode 'code_verifier=PKCE_CODE_VERIFIER'
```

A successful response contains an access token and refresh token. Store both securely against the connected user.

For a public client, omit the client secret and include `client_id` in the form body instead. Public clients still use PKCE.

### Step 5: Open the Trade WebSocket and attach your builder code

Use the user's OAuth `access_token` as the JWT. The WebSocket upgrade and the QFEX auth message both use the user's token; your builder code is added to the auth message.

```javascript theme={null}
import WebSocket from "ws";

const accessToken = user.qfexAccessToken;
const builderCode = process.env.QFEX_BUILDER_CODE;

const ws = new WebSocket(
  `wss://trade.qfex.com/?jwt=${encodeURIComponent(accessToken)}`,
);

ws.on("open", () => {
  ws.send(
    JSON.stringify({
      type: "auth",
      params: {
        jwt: accessToken,
        builder_code: builderCode,
      },
    }),
  );
});
```

If the user selected a QFEX subaccount, include its ID on the same auth message:

```json theme={null}
{
  "type": "auth",
  "params": {
    "jwt": "USER_OAUTH_ACCESS_TOKEN",
    "account_id": "22222222-2222-4222-8222-222222222222",
    "builder_code": "11111111-1111-4111-8111-111111111111"
  }
}
```

The builder code is now fixed for the lifetime of that WebSocket connection. Do not add it to each individual order.

### Step 6: Trade normally

After the auth response succeeds, place orders using the normal Trade WebSocket API.

```json theme={null}
{ "type": "auth", "result": "success" }
```

Orders, stop orders, and TWAPs submitted over the attributed connection inherit your builder code automatically. Builder rewards are credited to the QFEX account that owns the builder code.

OAuth does not bypass QFEX account requirements. If the account still needs identity verification, updated terms acceptance, or another required onboarding step, trading can be rejected until the user completes it on QFEX.

See:

* [Authenticate](/websocket/channels/trade/authenticate)
* [Add Order](/websocket/channels/trade/add_order)
* [Builder Codes API](/api-reference/builder-codes)

### Step 7: Refresh tokens and reconnect

OAuth access tokens expire. Use the refresh token to obtain a new access token before expiry or after an authentication failure.

For a confidential client:

```bash theme={null}
curl -X POST 'https://verify.qfex.com/auth/v1/oauth/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -u "$QFEX_OAUTH_CLIENT_ID:$QFEX_OAUTH_CLIENT_SECRET" \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'refresh_token=USER_REFRESH_TOKEN'
```

When you create a new Trade WebSocket with the refreshed access token, attach your builder code again in the new auth message.

If the user revokes your application in QFEX, stop trading for that user and send them through the OAuth flow again if they choose to reconnect.

## Existing users and new users use the same entry point

Your integration should expose one **Connect QFEX** action. Do not build separate "sign up" and "sign in" APIs on your side.

| User state                             | What happens                                                                                                                                                           |
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| No QFEX account                        | QFEX handles account creation and onboarding. During pre-release, the user may need to return to your application and select **Connect QFEX** again to complete OAuth. |
| Existing QFEX account                  | QFEX asks the user to sign in if necessary, then authorise your app.                                                                                                   |
| Already signed in to QFEX              | The user can go directly to the authorisation screen.                                                                                                                  |
| Existing valid grant                   | QFEX may complete the authorisation flow without asking for credentials again.                                                                                         |
| Grant revoked or refresh token invalid | Start a fresh authorization-code flow.                                                                                                                                 |

## Builder attribution is connection-scoped

Builder attribution is intentionally independent of account creation and OAuth.

This means:

* the end user's QFEX account is not permanently tied to a builder;
* the same user can trade through different builders at different times;
* a user trading directly on QFEX is not automatically attributed to your builder;
* every Trade WebSocket your integration opens must include your `builder_code`; and
* reconnecting without the code removes builder attribution from that new connection.

This also means you should set `builder_code` from trusted application configuration rather than accepting an arbitrary value from the browser or end user.

## Security checklist

Before going live:

* use Authorization Code + PKCE for every OAuth flow;
* validate `state` on every callback;
* register exact HTTPS redirect URIs and avoid wildcard callbacks;
* keep confidential-client secrets, access tokens, and refresh tokens server-side;
* encrypt refresh tokens at rest;
* never log access tokens, refresh tokens, authorization codes, or QFEX API secrets;
* do not ask users for QFEX passwords or MFA codes inside your application;
* reconnect the Trade WebSocket with the new access token after a refresh;
* attach your configured builder code on every new Trade WebSocket; and
* stop trading immediately if authorization is revoked.

<Note>
  The standard OAuth scopes describe identity information returned by the OAuth
  provider. They should not be treated as a read-only or trade-only permission
  boundary for QFEX trading. An access token used with QFEX trading APIs must be
  protected as a credential capable of acting as the user.
</Note>

## End-to-end checklist

A production integration is complete when you can test all of the following:

1. A user with no QFEX account can enter the QFEX account-creation flow from **Connect QFEX** and, once new-user OAuth continuation is released, return to the original authorisation request after onboarding.
2. An existing QFEX user can connect without sharing credentials with your application.
3. Your callback rejects an invalid `state` or PKCE verifier.
4. You can exchange the authorization code and securely store the returned token set.
5. You can authenticate `wss://trade.qfex.com` with the user's access token.
6. The Trade WebSocket auth message includes your builder UUID automatically.
7. A normal order, stop order, and TWAP placed through that connection are attributed to your builder.
8. Token refresh followed by WebSocket reconnection preserves builder attribution.
9. Revoking the connected application prevents continued use of the revoked authorization.

If you need an OAuth client registered for an integration, contact [support@qfex.com](mailto:support@qfex.com).
