Authentication
Every request to https://api.chalehq.com/api/v1 carries a bearer token:
Authorization: Bearer chk_live_a1b2c3d4_…
API keys (chk_<env>_<prefix>_<secret>) are minted by a business OWNER in the Chale Business app (More → Developers → API keys) or with POST /businesses/:businessId/api-keys. The full key is shown once; we store only an argon2id hash. The prefix is public — use it in logs and support tickets, never the secret. Keys are scoped:
| Scope | Allows |
|---|---|
availability:read | availability, slots, quotes |
bookings:read / bookings:write | bookings, holds, reschedule/cancel, payments recorded, payment links, subscription standing |
customers:read | the business's customers (minimal PII) |
catalog:read / catalog:write | units, services, providers, extras, blocks, uploads |
business:write | opening hours and policies (a key may not rename the business or change its deposit instructions) |
webhooks:manage | outbound webhook endpoints |
usage:write | internal (the assistant's usage meters) |
A key belongs to one business: :businessId in a path must be that business or the answer is 404 NOT_FOUND (never 403, so foreign ids cannot be probed). Missing scope → 403 SCOPE_MISSING listing what is missing. Revoked key → 401 API_KEY_REVOKED; malformed or unknown → 401 AUTH_INVALID_TOKEN.
User sessions (the apps) exchange a phone OTP for a 15-minute JWT + a rotating refresh token at POST /auth/firebase; integrators do not need them.
Routes marked user sessions only (creating a business, members, API keys, the sandbox) answer 403 FORBIDDEN to keys.