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

# Authentication

> HTTP Basic with a partner key + secret, scoped per business.

The Partner API uses **HTTP Basic authentication** over HTTPS. Every request
must include an `Authorization` header.

```http theme={null}
Authorization: Basic base64(API_KEY:API_SECRET)
```

`curl`, `requests`, `axios`, and most HTTP libraries handle the base64
encoding for you.

## Where credentials come from

Your klikit integration contact issues two values during onboarding:

* **`partner_api_key`** — the public half. Safe to log in your own systems.
* **`partner_api_secret`** — the secret half. Treat it like a password.
  Never commit it to git; rotate it via support if you suspect it leaked.

A credential is bound to **exactly one business** on klikit. You can ask for
multiple credentials if you serve multiple businesses.

## Scopes

Each credential is granted a subset of scopes. The endpoint that you're
calling must be covered by one of them, or the API returns `403`.

| Scope              | Grants                                                    |
| ------------------ | --------------------------------------------------------- |
| `brands:read`      | `GET /brands`, `GET /branches`                            |
| `menus:read`       | `GET /menus` (both modes)                                 |
| `menus:oos`        | `PATCH /items/{id}/availability` (single + bulk)          |
| `orders:read`      | `GET /orders`, `GET /orders/{id}`                         |
| `visibility:write` | Branch / brand visibility toggles                         |
| `webhooks:read`    | Read your registered webhook URLs (operator-driven today) |

If you call an endpoint your credential isn't scoped for you'll get:

```json theme={null}
{
  "error": {
    "code": "FORBIDDEN_SCOPE",
    "message": "credential is not scoped for menus:oos"
  }
}
```

Talk to your operator to widen the scope set.

## Worked example

```bash theme={null}
curl -sS \
  -u "$PARTNER_API_KEY:$PARTNER_API_SECRET" \
  "https://api.dev.shadowchef.co/v1/partner/brands"
```

```python theme={null}
import os, requests
r = requests.get(
    "https://api.dev.shadowchef.co/v1/partner/brands",
    auth=(os.environ["PARTNER_API_KEY"], os.environ["PARTNER_API_SECRET"]),
)
r.raise_for_status()
print(r.json())
```

```js theme={null}
import fetch from "node-fetch";
const auth = Buffer.from(
  `${process.env.PARTNER_API_KEY}:${process.env.PARTNER_API_SECRET}`
).toString("base64");
const res = await fetch("https://api.dev.shadowchef.co/v1/partner/brands", {
  headers: { Authorization: `Basic ${auth}` },
});
console.log(await res.json());
```

## Rotating a secret

The operator can re-issue your secret at any time. The old secret keeps
working for **15 minutes** after rotation so you can roll the new value
through your config without dropping requests; after that window it returns
`401`. Schedule rotations during a low-traffic period and update both halves
of your deployment before the window expires.

## What stops here

This endpoint family does **not** support OAuth2, JWT, or client certificates.
If your security policy requires one of those, raise it with
[integrations@klikit.io](mailto:integrations@klikit.io) — we don't have a
public timeline yet.
