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

# Authentication

> How to authenticate with the Supapost API.

The Supapost API supports two authentication methods.

## API key

For server-to-server integrations, use an API key. Create one in **Settings → Developer** in the dashboard — keys are prefixed `sp_live_...` and scoped to your team.

```bash theme={null}
curl https://api.supapost.so/projects \
  -H "Authorization: Bearer sp_live_..."
```

API keys are verified through [Unkey](https://unkey.dev) on every request and inherit all permissions of the team owner (full access to team resources).

## Supabase JWT

The web app authenticates via Supabase JWT tokens. The frontend manages these automatically — you only need to handle them yourself when building a custom integration against the same backend.

```bash theme={null}
curl https://api.supapost.so/projects \
  -H "Authorization: Bearer eyJhbGci..."
```

Tokens are verified against the Supabase project's public JWKS (ES256). No shared secret is required.

## Unauthenticated endpoints

A small number of routes are intentionally public:

| Path                               | Purpose                                                                                    |
| ---------------------------------- | ------------------------------------------------------------------------------------------ |
| `GET /health`                      | Liveness probe                                                                             |
| `GET /auth/tiktok/callback`        | TikTok OAuth redirect (state token verified via KV)                                        |
| `GET /auth/instagram/callback`     | Instagram OAuth redirect                                                                   |
| `GET /auth/shopify/callback`       | Shopify OAuth redirect                                                                     |
| `POST /webhooks/higgsfield/:jobId` | Higgsfield image-generation callback — protected by a per-job nonce in the `?token=` query |

All other routes require an `Authorization: Bearer ...` header and will return `401` without one.

## Rate limits

Limits are applied per-team across three buckets:

| Tier      | Limit        | Endpoints                                                            |
| --------- | ------------ | -------------------------------------------------------------------- |
| Expensive | 30 / minute  | `/generate/slides`, `/generate/image`, `/render`, `/stores/:id/sync` |
| Mutating  | 120 / minute | All POST / PATCH / DELETE writes                                     |
| Read      | 600 / minute | All GET requests                                                     |

Exceeding a limit returns a `429` response with a `Retry-After` header indicating when to retry:

```json theme={null}
{
  "success": false,
  "message": "Rate limit exceeded for expensive endpoints. Retry in 60s."
}
```

Rate limits are enforced by [Cloudflare's native rate-limiting API](https://developers.cloudflare.com/workers/runtime-apis/bindings/rate-limit/). Counters reset every 60 seconds.
