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

# BitRobot Connect

> Let users associate the wallet they use on your subnet to their BitRobot account so the Subnet Points and Bolts you grant reach them

BitRobot Connect links the wallet a user has on your subnet to their BitRobot account.

## Prerequisites

* Your subnet is [registered](/subnet-integration#1-register-your-subnet) and you know its **Subnet ID**.
* An [API key](/subnet-integration#2-get-and-manage-your-api-key) for the subnet, kept server-side.
* A **connect URL** you host: an `https` page on your own domain, with no query string or fragment, behind your normal login. Send that URL to the BitRobot team.

## How it works

1. The user presses **Connect** next to your subnet on their BitRobot profile page. BitRobot redirects the browser to your connect URL with `request_id` and `nonce` in the query string.
2. Your connect page stores `request_id` and `nonce` in the user's server-side session and shows a **Connect** button.
3. When the user presses **Connect**, your backend calls the confirm endpoint with your API key and the user's wallet address.
4. Your backend redirects the browser to the `return_url` from the response. BitRobot completes the connection as the page loads.

A connect request expires 30 minutes after the user presses **Connect** in BitRobot. The `auth_code` in the confirm response is single-use and expires 5 minutes after the confirm call.

## Step 1 — Build the connect page

BitRobot opens your connect URL like this:

```text theme={null}
https://your-subnet.com/bitrobot/connect?request_id=01ARZ3NDEKTSV4RRFFQ69G5FAV&nonce=Qm3xk7w2Zr9vL1nB8pT4yH6sD0aF5cG2jK8mN1oP3qR
```

The page must:

1. Require login. If the user is signed out, send them through login and back to this URL with the query string intact. See [Returning from login](/bitrobot-connect-examples#returning-from-login).
2. Store `request_id` and `nonce` in the server-side session for the signed-in user.
3. Show the user's wallet address and a **Connect** button that POSTs to your confirm handler.

```javascript routes/bitrobot-connect.js theme={null}
router.get("/bitrobot/connect", requireLogin, (req, res) => {
  const { request_id: requestId, nonce } = req.query;
  if (typeof requestId !== "string" || typeof nonce !== "string") {
    return res.status(400).send("Missing request_id or nonce");
  }

  req.session.bitrobotConnect = { requestId, nonce };
  res.render("bitrobot-connect", { walletAddress: req.user.walletAddress });
});
```

Template: [Connect page](/bitrobot-connect-examples#connect-page).

If your API is stateless, store the values in a table instead of the session. See [Stateless hold](/bitrobot-connect-examples#stateless-hold).

## Step 2 — Confirm the wallet

When the user presses **Connect**, read `request_id` and `nonce` from the session and call the confirm endpoint from your backend:

```http theme={null}
POST https://api.bitrobot.ai/subnets/{subnet_id}/connect/confirm
Authorization: Bearer brb_your_api_key
Content-Type: application/json

{
  "request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
  "nonce": "Qm3xk7w2Zr9vL1nB8pT4yH6sD0aF5cG2jK8mN1oP3qR",
  "wallet_address": "HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH"
}
```

| Field            | Required | Description                                                                     |
| ---------------- | -------- | ------------------------------------------------------------------------------- |
| `request_id`     | Yes      | From the session                                                                |
| `nonce`          | Yes      | From the session                                                                |
| `wallet_address` | Yes      | The user's Solana wallet address on your subnet, base58-encoded                 |
| `subnet_user_id` | No       | Your own identifier for the user. Truncated to 128 characters. No personal data |

If you send an `Idempotency-Key` header, use a new value on every attempt, including retries.

A successful response returns `200`:

```json theme={null}
{
  "status": "success",
  "return_url": "https://app.bitrobot.ai/connect/callback?request_id=01ARZ3NDEKTSV4RRFFQ69G5FAV#ac=8Kd2mQx7f3RcVn0Pz_s1TgW6bHuJ4eLpAo9iNr-k5Zw",
  "auth_code": "8Kd2mQx7f3RcVn0Pz_s1TgW6bHuJ4eLpAo9iNr-k5Zw",
  "expires_at": "2026-09-02T10:30:00Z"
}
```

Full reference: [Confirm a wallet connection](/api-reference/connect/confirm-wallet-connection).

## Step 3 — Redirect to BitRobot

Check the response body for `auth_code`, not the HTTP status:

* **`auth_code` is present.** Clear the session values, check that `return_url` starts with `https://` or `http://`, and redirect the browser to it. Use a `303` redirect from your handler. For a client-side page, return `return_url` from your handler and call `window.location.replace(url)`.
* **`auth_code` is absent.** Show an error page with the `error` message from the response. Template: [Error page](/bitrobot-connect-examples#error-page).

```javascript routes/bitrobot-connect.js theme={null}
router.post("/bitrobot/connect/confirm", requireLogin, async (req, res) => {
  const pending = req.session.bitrobotConnect;
  if (!pending) return res.status(400).send("No connection in progress");

  const response = await fetch(`${BITROBOT_API_BASE}/subnets/${BITROBOT_SUBNET_ID}/connect/confirm`, {
    method: "POST",
    headers: { Authorization: `Bearer ${BITROBOT_API_KEY}`, "Content-Type": "application/json" },
    body: JSON.stringify({
      request_id: pending.requestId,
      nonce: pending.nonce,
      wallet_address: req.user.walletAddress,
    }),
  });
  const body = await response.json();

  if (!body.auth_code || !/^https?:\/\//.test(body.return_url)) {
    return res.status(400).render("bitrobot-connect-error", { error: body.error });
  }

  delete req.session.bitrobotConnect;
  res.redirect(303, body.return_url);
});
```

<Warning>
  Redirect to `return_url` verbatim, fragment included. Do not log, display, or store `auth_code`.
</Warning>

Complete implementations in seven languages are in the [examples](/bitrobot-connect-examples#backend-implementations).

## Errors

`404`, `409`, `410`, and `422` responses have this shape. Other errors carry `error` only.

```json theme={null}
{
  "error": "Connect request not found",
  "reason": "request_not_found"
}
```

| Status        | `reason`                              | What to do                                                                                 |
| ------------- | ------------------------------------- | ------------------------------------------------------------------------------------------ |
| `409`         | `already_confirmed`, with `auth_code` | Redirect to `return_url`                                                                   |
| `409`         | `already_confirmed`, no `auth_code`   | Ask the user to press **Connect** next to your subnet again on their BitRobot profile page |
| `404`         | `request_not_found`                   | Ask the user to press **Connect** next to your subnet again on their BitRobot profile page |
| `410`         | `request_expired`                     | Ask the user to press **Connect** next to your subnet again on their BitRobot profile page |
| `422`         | `nonce_mismatch`                      | Ask the user to open the newest link from BitRobot                                         |
| `422`         | `invalid_address`                     | Check the `wallet_address` you sent                                                        |
| `422`         | `invalid_request`                     | Check the request body. `error` names the field                                            |
| `400` / `401` | —                                     | Check your Subnet ID and API key                                                           |
| `403`         | —                                     | Check your Subnet ID, or use an API key created by a current admin of your subnet          |
| `429`         | —                                     | Retry after `Retry-After`                                                                  |
| `5xx`         | —                                     | Retry with backoff                                                                         |

## Test on staging

1. Ask the BitRobot team to register your subnet on staging and use the Subnet ID they issue. Create a staging [API key](/subnet-integration#2-get-and-manage-your-api-key) and set `BITROBOT_API_BASE=https://api-stage.bitrobot.ai`.

2. Call the confirm endpoint with a made-up `request_id`. A `404 request_not_found` confirms your key and Subnet ID are valid.

   ```bash theme={null}
   curl -sS -X POST "https://api-stage.bitrobot.ai/subnets/$BITROBOT_SUBNET_ID/connect/confirm" \
     -H "Authorization: Bearer $BITROBOT_API_KEY" -H "Content-Type: application/json" \
     -d '{"request_id":"01ARZ3NDEKTSV4RRFFQ69G5FAV","nonce":"test","wallet_address":"HN7cABqLq46Es1jh92dQQisAq662SmxELLLsHHe4YWrH"}'
   ```

3. Send the BitRobot team your staging connect URL and wait for them to enable it.

4. Sign in at `https://stage.bitrobot.ai`, open your profile page, press **Connect** next to your subnet, then press **Connect** on your page. The subnet shows **Connected**.

5. Send a [Subnet Points grant](/api-reference/points/grant-subnet-points) by `wallet_address` for that wallet. The points appear on the user's dashboard.

Repeat with a production key, `https://api.bitrobot.ai`, and your production connect URL.

## Next steps

<Columns cols={2}>
  <Card title="Examples" icon="code" href="/bitrobot-connect-examples">
    Complete implementations in seven languages, the pages you render, and tests worth shipping.
  </Card>

  <Card title="Points system" icon="trophy" href="/points-system">
    How Subnet Points are granted and convert to Bolts.
  </Card>
</Columns>
