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

# Authentication

> How to authenticate to the PayPunch API with JWT bearer tokens — admin (bookkeeper) versus employee sessions.

PayPunch uses **JSON Web Tokens (JWT)**. You obtain a token from a login
endpoint, then send it on every authenticated request.

## Token types

There are two principal token types, distinguished by the `type` claim inside
the JWT:

| Type       | Obtained from                                     | Used for                                       |
| ---------- | ------------------------------------------------- | ---------------------------------------------- |
| `admin`    | `POST /api/v1/auth/login` (email + password)      | Bookkeeper admin endpoints (`/api/v1/admin/*`) |
| `employee` | `POST /api/v1/auth/employee/verify` (phone + PIN) | Employee endpoints (`/api/v1/employee/*`)      |

<Note>
  A `client` token type also exists in the auth layer, but the documented
  `/api/v1` endpoints only require `admin` or `employee` tokens.
</Note>

Tokens are signed with `HS256` and expire after `JWT_EXPIRES_IN` (default
**7 days**). The token payload includes `userId`, `type`, and — depending on the
type — `bookkeeperOrgId`, `companyId`, and `email`.

## Sending the token

Send the JWT in the `Authorization` header as a bearer token:

```http theme={null}
Authorization: Bearer eyJhbGciOiJ...
```

<Tip>
  The header parser also accepts a raw token without the `Bearer ` prefix, but
  `Bearer <token>` is the recommended, standard form.
</Tip>

### Cookie fallback

The login endpoints also set an `httpOnly` cookie named `auth-token` (7-day
max-age, `SameSite=Lax`, `Secure` in production). If no `Authorization` header
is present, the server falls back to this cookie. Browser-based clients on the
same origin are therefore authenticated automatically; API integrations should
prefer the explicit `Authorization` header.

The header takes priority over the cookie when both are present.

## Authorization rules

Endpoints enforce the required token type. Requesting an `admin` endpoint with
an `employee` token (or vice-versa) is rejected.

<ResponseField name="Missing token" type="401 Authentication required">
  No `Authorization` header and no `auth-token` cookie, or the token is invalid
  or expired.
</ResponseField>

<ResponseField name="Wrong token type" type="401 / Access denied">
  Token is valid but its `type` claim does not match the endpoint's required
  type (`Access denied. Required role: <type>`).
</ResponseField>

<ResponseField name="Cross-tenant access" type="403 Access denied">
  Admins can only read/write data belonging to their own `bookkeeperOrgId`;
  employees only their own company. Accessing another tenant's resource returns
  `403`.
</ResponseField>

Some endpoints are public or have **optional** auth — for example
`GET /api/v1/admin/industries` works with or without a token.

## Example: authenticate and call an endpoint

<CodeGroup>
  ```bash 1. Get an admin token theme={null}
  curl -X POST https://app.paypunch.io/api/v1/auth/login \
    -H "Content-Type: application/json" \
    -d '{
      "email": "sarah@acmebookkeeping.com",
      "password": "Admin123!"
    }'
  ```

  ```bash 2. Call an admin endpoint theme={null}
  curl https://app.paypunch.io/api/v1/admin/bookkeeper-orgs \
    -H "Authorization: Bearer eyJhbGciOiJ..."
  ```
</CodeGroup>

The token is in `data.token` of the login response.

<Card title="Admin login" icon="right-to-bracket" href="/api-reference/auth-login">
  Full reference for `POST /api/v1/auth/login`.
</Card>
