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

> ## Agent Instructions
> DualMind Arena API base URL: https://api.dualmindlab.tech. Public endpoints only; admin routes are not part of this API.
> Authenticate with the access token from an Arena session (a Supabase JWT) as `Authorization: Bearer <token>`. There are no API keys yet; never invent one.
> For battles call POST /api/arena/dualchat, then vote with POST /api/arena/model-vote using the returned comparisonId. Keep model names hidden from voters until they vote.
> GET /api/arena/model-stats (leaderboard) and GET /health need no token.

# Authentication

> Authenticate API requests with the access token from your DualMind Arena session.

The API uses the same sign-in as the Arena. When you sign in, Supabase Auth issues a short-lived **access token** (a JWT). Send it as a Bearer token:

```http theme={null}
Authorization: Bearer <access token>
```

<RequestExample>
  ```bash Authenticated request theme={null}
  curl https://api.dualmindlab.tech/api/models \
    -H "Authorization: Bearer $DUALMIND_TOKEN"
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK theme={null}
  {
    "items": [
      {
        "modelId": "c6e0cc03-3b12-41bf-b119-d0d02bec039b",
        "modelName": "llama-3.3-70b-versatile",
        "displayName": "Llama 3.3 70B Versatile",
        "providerName": "groq",
        "isFree": true,
        "status": "active"
      }
    ]
  }
  ```

  ```http 401 Unauthorized theme={null}
  HTTP/2 401
  www-authenticate: Bearer error="invalid_token", error_description="The token expired"
  ```
</ResponseExample>

## Which endpoints need a token

| Needs a token | No token needed |
| :- | :- |
| Battles and chat (`/api/arena/dualchat`, `/chat`, `/chat/stream`) | Leaderboard (`GET /api/arena/model-stats`) |
| Voting (`POST /api/arena/model-vote`) | Health (`GET /health`) |
| Models (`GET /api/models`) | Feature flags (`GET /api/settings/feature-flag/{key}`) |
| Your threads (list, create, rename, share, delete) | Shared threads (`public` or `unlisted`) |

## Get your token

<Steps>
  <Step title="Sign in to the Arena">
    Open [arena.dualmindlab.tech](https://arena.dualmindlab.tech) and sign in.
  </Step>

  <Step title="Open the browser console">
    Press <kbd>F12</kbd> (or <kbd>⌘</kbd> <kbd>⌥</kbd> <kbd>J</kbd> on a Mac) and choose **Console**.
  </Step>

  <Step title="Copy the token">
    Run this in the console. It copies the current access token to your clipboard:

    ```javascript Browser console icon="square-terminal" theme={null}
    copy(await DualMindAuth.getAccessToken())
    ```
  </Step>

  <Step title="Keep it out of your code">
    Store it in an environment variable, not in source control:

    ```bash .env / shell icon="key-round" theme={null}
    export DUALMIND_TOKEN="eyJhbGciOi..."
    ```
  </Step>
</Steps>

<Warning>
  Your access token acts as **you**: anyone holding it can start battles, vote and read your private threads until it expires. Keep it in an environment variable and never paste it into shared code, issues or chats.
</Warning>

## Check that it works

<CodeGroup>
  ```bash cURL theme={null}
  curl -i https://api.dualmindlab.tech/api/models \
    -H "Authorization: Bearer $DUALMIND_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://api.dualmindlab.tech/api/models", {
    headers: { Authorization: `Bearer ${process.env.DUALMIND_TOKEN}` },
  });
  console.log(res.status, res.ok ? (await res.json()).items.length + " models" : res.headers.get("www-authenticate"));
  ```

  ```python Python theme={null}
  import os, requests

  r = requests.get(
      "https://api.dualmindlab.tech/api/models",
      headers={"Authorization": f"Bearer {os.environ['DUALMIND_TOKEN']}"},
      timeout=30,
  )
  print(r.status_code, len(r.json()["items"]) if r.ok else r.headers.get("WWW-Authenticate"))
  ```
</CodeGroup>

A `200` with a list of models means you're in. A `401` means the token is missing, malformed or expired.

## Token lifetime

<AccordionGroup>
  <Accordion title="Tokens expire" icon="hourglass">
    Access tokens are short-lived (typically about an hour). The Arena refreshes its own session automatically; for scripts, copy a fresh token when you get a `401`.
  </Accordion>

  <Accordion title="Reading a 401" icon="circle-alert">
    Authentication failures return `401` with an empty body. The `WWW-Authenticate` response header says why, for example `Bearer error="invalid_token", error_description="The token expired..."`.
  </Accordion>

  <Accordion title="Long-lived API keys" icon="key">
    Personal API keys for scripts and integrations are planned. See the [roadmap](/roadmap).
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.