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

# Authentication

> API keys, scopes and restrictions.

Every request carries a LazyApp API key as a Bearer token:

```bash theme={null}
curl https://lazyapp.in/v1/contacts \
  -H "Authorization: Bearer sk_live_..."
```

HTTPS only. There is no cookie, session or signed-request alternative for the REST API.

Console sign-in (password, Google, passkeys, two-step verification) is covered under [Security](https://docs.lazyapp.in/security/overview.md). This page is only about API keys.

## Key types

| Prefix | Mode | Reaches a real phone |
| - | - | - |
| `sk_test_` | `test` | No |
| `sk_live_` | `live` | Yes |

The prefix is not decoration — it determines the workspace mode the key operates in. A test key cannot read live data and a live key cannot read test data, so the two never mix.

### Keys and your plan

Test keys are free on every workspace, with or without a plan. Test mode runs on the shared test number and is never plan-limited, so you can build the whole integration before you pay anything.

Live keys need the **Pro** plan. On any smaller plan, or no plan, a live key gets `402` with `code: plan_limit_reached`. Connecting your own WhatsApp number needs a plan too. See [Plans and limits](https://docs.lazyapp.in/billing/pricing-and-tiers.md#plan-limit-reached).

> [!WARNING]
>
> A key is displayed once, when you create it. LazyApp stores only a hash, so a lost key
> cannot be recovered — create a new one and revoke the old.

## Scopes

Each key carries scopes. A request for an endpoint outside them returns `403`.

| Scope | Grants |
| - | - |
| `messages:send` | Send messages, create contacts, trigger workflows and events |
| `messages:read` | Read messages, contacts, conversations, workflows and capabilities |
| `templates:read` | Read templates |
| `templates:write` | Create, sync and delete templates |
| `media:write` | Upload and delete media |
| `webhooks:write` | Manage webhook endpoints and read deliveries |
| `flows:write` | Manage WhatsApp Flows and read responses |
| `customers:write` | Manage platform customers, setup links and embed tokens |
| `customers:act` | Act on behalf of a platform customer without managing them |
| `billing:read` | Read billing and usage |

Grant the narrowest set that works. A key used only for OTP delivery needs `messages:send` and nothing else.

The scope each endpoint requires is listed on its [reference page](https://docs.lazyapp.in/api-reference/messages/send-a-message.md).

## Restrictions

Beyond scopes, a key can be restricted to:

* **Specific phone numbers.** A send from a number outside the list returns `403`, even with `messages:send`. Useful when one key serves one product line.
* **Specific IP addresses.** Requests from anywhere else are rejected.
* **A single platform customer.** Keys minted through
  [`POST /v1/platform/customers/{customer}/api-keys`](https://docs.lazyapp.in/api-reference/platform/issue-an-api-key-for-a-customer)
  can only see that customer's workspace.

## Acting for a platform customer

If you resell LazyApp, a platform key can call any `/v1` endpoint on a customer's behalf by passing their identifier:

```bash theme={null}
curl https://lazyapp.in/v1/contacts \
  -H "Authorization: Bearer sk_live_..." \
  -H "X-LazyApp-Customer: acct_8812"
```

`X-LazyApp-Customer` accepts the customer's `public_id`, `uuid` or `external_id`. You can also pass `?customer=` on the query string.

The key needs `customers:act` or `customers:write`. Use `customers:act` when the key only sends on customers' behalf — it cannot rename, suspend or delete them. See [Platforms](https://docs.lazyapp.in/platform/overview.md).

## Failed attempts

Requests with a missing or invalid key never reach the per-key rate limiter — they are throttled per IP instead. Brute-forcing a key gets you rate limited quickly.

## What a failure looks like

```json 401 Unauthenticated theme={null}
{ "message": "Unauthenticated." }
```

```json 403 Wrong scope theme={null}
{ "message": "This API key is missing the required scope." }
```

```json 403 Restricted number theme={null}
{ "message": "This API key is not allowed to use that phone number." }
```

See [Errors](https://docs.lazyapp.in/concepts/errors.md) for the full list.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.