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

# Authentication

> API keys, session tokens, and which endpoints are public.

Every protected endpoint accepts the same header:

```
Authorization: Bearer <token>
```

Two kinds of token work there, and the API treats them identically. There is no
separate "API key" endpoint for anything.

| Token             | Looks like   | Use it for                                      |
| ----------------- | ------------ | ----------------------------------------------- |
| **API key**       | `tru_...`    | Servers, agents, CI, anything long-lived        |
| **Session token** | a signed JWT | The dashboard, and short-lived browser sessions |

## Creating an API key

<Steps>
  <Step title="Sign in">
    Get a session token from `POST /api/auth/signin`:

    ```bash theme={null}
    curl -X POST https://api.truscan.co/api/auth/signin \
      -H "Content-Type: application/json" \
      -d '{"email": "you@example.com", "password": "..."}'
    ```

    The token is at `result.token`.
  </Step>

  <Step title="Create the key">
    ```bash theme={null}
    curl -X POST https://api.truscan.co/api/auth/keys \
      -H "Authorization: Bearer $SESSION_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{"name": "production"}'
    ```

    `name` is optional and capped at 60 characters; omit it and the key is
    called `Untitled key`.
  </Step>

  <Step title="Store the secret">
    The response contains `result.secret`. This is the **only** time it is
    returned. Later calls to `GET /api/auth/keys` show just `last_four`.
  </Step>
</Steps>

<Note>
  An account may hold up to **25 live keys**. Revoke keys you no longer use with
  `DELETE /api/auth/keys/{id}`.
</Note>

## Public endpoints

These need no `Authorization` header:

* `POST /api/auth/signup`
* `POST /api/auth/signin`
* `POST /api/auth/forgot-password`
* `POST /api/auth/reset-password`
* `GET /health`, `/healthz`, `/readyz`

`POST /api/billing/webhook` is also unauthenticated in the bearer sense. It is
verified instead by the `webhook-id`, `webhook-timestamp`, and
`webhook-signature` HMAC headers, and is meant only for the payment provider.

## Handling a 401

A missing, malformed, revoked, or expired token returns `401` with the standard
error envelope:

```json theme={null}
{
  "success": false,
  "message": "Your API key is invalid or has been revoked.",
  "result": { "code": "unauthorized" }
}
```

Revocation takes effect immediately. A revoked key fails the next request.

<Warning>
  Treat `tru_` keys like passwords. Keep them in environment variables or a
  secret manager, never in client-side code, a repository, or a URL query
  string.
</Warning>
