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

# Authentication

> API keys, live and test modes, scopes, rotation and how to store keys safely.

Authenticate every request with an API key in the `Authorization` header, using the Bearer scheme:

```bash theme={null}
curl https://api.teambuilder.ge/v1/ping \
  -H "Authorization: Bearer tb_live_..."
```

Keys belong to one company. The company is resolved from the key alone, so no request ever names a company, and a key can never read another company's data.

## Live and test keys

| Prefix | Mode | Reads and writes |
| - | - | - |
| `tb_live_` | `live` | Your real company: real employees, XP, coins and shop. |
| `tb_test_` | `test` | Your [sandbox company](/guides/sandbox): sample employees and departments, same endpoints and response shapes. |

Build and test against a `tb_test_` key, then swap in the `tb_live_` key at go-live; nothing else changes. `GET /v1/ping` reports a key's `mode`, so a deployment can assert it is using the key it expects.

## Getting a key

TeamBuilder issues keys during onboarding. Email [contact@teambuilder.ge](mailto:contact@teambuilder.ge) with your company name, the scopes you need and a technical contact.

* A key is shown **once**, when it is issued. TeamBuilder stores only a hash of it, so a lost key cannot be recovered; ask for a new one.
* A company normally holds one live and one test key. A second key per mode is issued only for a rotation.
* A key may carry an expiry date. An expired key behaves like a revoked one.

## Scopes

Each key carries a set of scopes. A request to an endpoint whose scope the key lacks returns `403 forbidden`.

| Scope | Grants | Default |
| - | - | - |
| `employees:read` | List and look up employees; read an employee's stats and badges. | Yes |
| `leaderboard:read` | Read leaderboards, company-wide, filtered by department and grouped by department. | Yes |
| `departments:read` | List departments, including archived ones on request. | Yes |
| `shop:read` | Read your shop catalogue with your prices and stock. | Yes |
| `employees:write` | [Sync your roster](/guides/roster-sync): add, update, deactivate and reactivate employees. | No, on request |

`GET /v1/ping` works with any valid key, whatever its scopes.

<Note>
  `leaderboard:read` also reveals your active department names, because the [by-department leaderboard](/guides/leaderboards#grouped-by-department) lists every department. Ask for a key without it if a consumer must not see your structure.
</Note>

Ask for the narrowest set each integration needs. An intranet widget needs only the read scopes it renders; only the system that runs your roster sync needs `employees:write`, ideally on a key of its own.

## 401 or 403?

| Status | `code` | Meaning | What to do |
| - | - | - | - |
| `401` | `unauthorized` | No key, a malformed header, or a key that is unknown, revoked or expired. The response carries `WWW-Authenticate: Bearer realm="TeamBuilder API"`. | Check the header is exactly `Authorization: Bearer <key>` and that the key is current. Do not retry automatically. |
| `403` | `forbidden` | The key is valid but lacks the endpoint's scope. | Ask for the scope to be added, or use a key that has it. |

## Storing keys

<AccordionGroup>
  <Accordion title="Keep keys on the server" icon="server">
    Call the API from your backend, never from a browser or a mobile app. The API does not accept cross-origin browser requests, so browser calls fail by design.
  </Accordion>

  <Accordion title="Use a secret manager" icon="vault">
    Load keys at runtime from your secret manager (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, HashiCorp Vault, Doppler, or your platform's encrypted variables). Never commit a key or bake it into an image.
  </Accordion>

  <Accordion title="Scan for leaks" icon="magnifying-glass">
    The prefixes make leaked keys easy to detect. Add a custom pattern to your secret scanner:

    ```text theme={null}
    tb_(live|test)_[0-9A-Za-z]{43}
    ```

    If a key leaks, email [contact@teambuilder.ge](mailto:contact@teambuilder.ge) so it can be revoked at once, then rotate.
  </Accordion>

  <Accordion title="Keep keys out of logs" icon="file-shield">
    Redact the `Authorization` header in request logging and APM tools. TeamBuilder never logs key material; quote the `request_id` instead when you need help with a request.
  </Accordion>
</AccordionGroup>

## Rotating a key

Rotation needs no downtime: both keys stay valid until the old one is revoked.

<Steps>
  <Step title="Request a new key">
    Ask [contact@teambuilder.ge](mailto:contact@teambuilder.ge) for a replacement with the same scopes.
  </Step>

  <Step title="Deploy it">
    Put the new key in your secret manager and roll it out to every service that calls the API.
  </Step>

  <Step title="Verify">
    Call `GET /v1/ping` from each service and check `mode` and `scopes`.
  </Step>

  <Step title="Revoke the old key">
    Ask for the old key to be revoked. From then on it returns `401`.
  </Step>
</Steps>

Rotate on a schedule that suits your security policy, at once when someone with access to a key leaves, and immediately if a key may have leaked.


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