> For the complete documentation index, see [llms.txt](https://docs.butlr.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.butlr.io/integrations-api-third-party-sensors/authentication.md).

# Authentication & Rate Limits

## Authentication

The Integrations API uses the same Butlr login system as the rest of the Butlr API; there is no separate login. It accepts **client-credentials tokens only**:

* **Which token:** use the **OAuth 2.0 Client Credentials Grant** described in [Authentication](https://docs.butlr.io/integrations-api-third-party-sensors/pages/M4RRvTv4ixsSzchgNwKb#oauth-2.0-client-credentials-grant). [Mint client credentials](/getting-started/mint-client-credentials.md), then exchange them at `POST https://api.butlr.io/api/v2/clients/login` with `"audience": "https://butlrauth/"`.
* **What doesn't work:** user tokens from the password login (`POST /api/v2/login`) work with the GraphQL and Reporting APIs but are **rejected here** with `401` / `-3`.

Send the token on every request:

```http
Authorization: Bearer [insert access_token here]
```

Every query is scoped to the Butlr client ID carried in the token, so you only ever receive your own data.

Authentication failures return one of these:

| HTTP  | Code    | Meaning                                                                                             |
| ----- | ------- | --------------------------------------------------------------------------------------------------- |
| `401` | `-3`    | Token missing, expired, not valid, or not accepted by this API (for example a password-login token) |
| `400` | `-2`    | Token is malformed and cannot be parsed                                                             |
| `400` | `-5102` | Token carries no usable client ID                                                                   |

```json
{ "errors": [{ "code": -3, "description": "jwt_invalid_error=…" }] }
```

If you get `-3`, first check that you are using a client-credentials token, not a password-login token; retrying won't fix that. A `-3` can also occur briefly if Butlr cannot verify your client at that moment, so if the token is right, retry after a short wait.

## Rate limits

Requests are limited per client with a token bucket:

* **Burst:** up to **30** requests at once.
* **Refill:** **1 request per second** (60 per minute). After a burst, you can send one more request each second.

A client that sends no more than one request per second is never limited. Over the limit, the API returns `429 Too Many Requests` with code `-5200` and a `Retry-After: 60` header. You don't have to wait the full 60 seconds: capacity returns at one request per second.

One request can ask for several measurements at once (see [Combining measurements](/integrations-api-third-party-sensors/reporting-api.md#combining-measurements)), which is usually cheaper than making several calls.

## Calling from a browser

The API is meant for server-to-server use. Browser requests are only allowed from Butlr's own origins, so a request from your own web page fails the browser's CORS check. Call the API from your backend instead.

## Support

Every response includes an `X-Request-ID` header. Include it when you contact [support](https://support.butlr.io/hc/en-us) about a specific request.
