# REST API basics

> Authentication, pagination, rate limiting, and error handling - the mechanics shared by every AssetLab API endpoint.

Source: https://app.assetlab.ca/docs/reference/rest-api

The AssetLab REST API exposes your organization's data for integrations, BI, and automation. Every endpoint shares the mechanics on this page; per-endpoint schemas live in the [interactive API reference](/docs/reference/api).

## Base URL and versioning

The API is served under a versioned base path (`.../v1`). The exact base URL for your organization is shown in **Settings → API Keys**. Breaking changes get a new version; `v1` stays stable.

## Authentication

Every request carries an [API key](/docs/manage/api-keys) as a Bearer token:

```bash
curl -H "Authorization: Bearer al_live_xxxxx" \
  "https://<api-base>/v1/assets"
```

The key determines the **organization** (permanently bound) and the **scopes** ([list](/docs/reference/scopes)). There is no other tenancy mechanism - no header, no parameter.

## Requests and responses

- JSON in, JSON out. `Content-Type: application/json` on writes.
- Standard verbs: `GET` (list/fetch), `POST` (create), `PATCH` (update), `DELETE` (remove).
- IDs are UUIDs. Get them from list endpoints - never construct or guess them.

## Pagination

List endpoints paginate with `page` and `per_page`:

| Parameter | Default | Max |
|---|---|---|
| `page` | 1 | - |
| `per_page` | 25 | 1000 |

Every list response carries a `pagination` object:

```json
{
  "data": [ ... ],
  "pagination": { "page": 1, "per_page": 25, "total": 142, "total_pages": 6 }
}
```

Iterate until `page == total_pages`. For large syncs, prefer big `per_page` values over many small pages - friendlier to your rate limit.

## Rate limiting

Each key has a per-minute limit (default 60 req/min), reported on every response:

| Header | Meaning |
|---|---|
| `X-RateLimit-Limit` | Requests allowed per window |
| `X-RateLimit-Remaining` | Left in the current window |
| `X-RateLimit-Reset` | Unix time the window resets |

On `429`, back off until the reset time. Well-behaved clients watch `Remaining` and pace proactively.

## Errors

Errors return a JSON body with an `error` string and a conventional status:

| Status | Meaning |
|---|---|
| 400 | Bad request - malformed UUID, invalid payload |
| 401 | Missing or invalid API key |
| 403 | Key inactive, expired, or missing the required scope |
| 404 | Resource not found (in *your* organization - IDs from elsewhere 404) |
| 429 | Rate limit exceeded |
| 500 | Server error - safe to retry with backoff |

Handle 403 specially in integrations: it usually means a scope gap, which is a configuration fix, not a retry.

## Writing data well

1. **Look up before you link.** Creating an asset means first fetching real site/building/system IDs from their list endpoints.
2. **Don't send tenant identifiers.** They're ignored; the key decides.
3. **Use bulk endpoints** for migrations - hundreds of records per call instead of hundreds of calls.
4. **Idempotency by design** - on retryable failures, re-query before re-creating to avoid duplicates.

## Related

- [Resources](/docs/reference/resources) - what's exposed
- [Interactive API reference](/docs/reference/api) - every endpoint, schema, and a try-it console
- [Webhooks](/docs/manage/webhooks) - push instead of poll
