# Quickstart

From nothing to a first successful call.

## 1. Get credentials

Integration clients are registered by us, not self-service. Email {{ support_email }} with:

- **which company** the integration is for,
- **what it needs to do** — we grant only the scopes that covers (see {doc}`scopes`).

You get back three things:

| | |
|---|---|
| `client_id` | e.g. `cust-acme-integration` |
| `client_secret` | **shown once**, stored hashed on our side — unrecoverable, so save it immediately |
| scopes | e.g. `shifts.read timesheets.read` |

One set of credentials belongs to exactly one company and cannot reach another, even if you belong to several.

## 2. Get an access token

`POST` to the identity provider's token endpoint. Credentials go in the form body:

```bash
curl -X POST https://auth.shiftavo.com/identity/o/api/token \
  -d grant_type=client_credentials \
  -d client_id=cust-acme-integration \
  -d client_secret=$CLIENT_SECRET \
  -d scope=shifts.read
```

```json
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 1800,
  "scope": "shifts.read"
}
```

```{important}
Cache the token and reuse it until shortly before it expires. This is a requirement, not an optimization — do not call the token endpoint once per request.
```

## 3. Find out which host to call

The access token is a JWT carrying an **`api_base`** claim that names your company's shard:

```json
{ "api_base": "https://app.shiftavo.com", "tenant_id": "0194d1c0-…", "…": "…" }
```

Read the host from the token rather than hardcoding it — that is what lets us add or move shards without you changing anything. Decode the payload as a routing hint only; you do not need to verify your own token.

## 4. Make a call

```bash
curl "$API_BASE/api/public/v1/locations/?page_size=100" \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

```json
{
  "object": "list",
  "data": [
    { "object": "location", "id": "0194d1c0-…", "name": "Bar — Hamptons" }
  ],
  "has_more": false,
  "next": null
}
```

If your own locations come back, the credentials, the scopes, and the company binding are all correct.

## The same thing in Python

```python
import requests

AUTH = "https://auth.shiftavo.com"

token = requests.post(
    f"{AUTH}/identity/o/api/token",
    data={
        "grant_type": "client_credentials",
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "scope": "shifts.read",
    },
    timeout=30,
).json()

# `api_base` is a routing hint from the token — decode, don't verify.
import base64, json
payload = token["access_token"].split(".")[1]
api_base = json.loads(base64.urlsafe_b64decode(payload + "=" * (-len(payload) % 4)))["api_base"]

shifts = requests.get(
    f"{api_base}/api/public/v1/shifts/",
    headers={"Authorization": f"Bearer {token['access_token']}"},
    timeout=30,
).json()
```

## Next

- {doc}`authentication` — the token flow in full, including expiry and `401` handling.
- {doc}`conventions` — pagination, errors, idempotency. Read this before writing a client.
- <a href="../../api/index.html">API Reference</a> — every endpoint.
