Skip to main content
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.
curl https://api.supapost.so/projects \
  -H "Authorization: Bearer sp_live_..."
API keys are verified through Unkey 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.
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:
PathPurpose
GET /healthLiveness probe
GET /auth/tiktok/callbackTikTok OAuth redirect (state token verified via KV)
GET /auth/instagram/callbackInstagram OAuth redirect
GET /auth/shopify/callbackShopify OAuth redirect
POST /webhooks/higgsfield/:jobIdHiggsfield 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:
TierLimitEndpoints
Expensive30 / minute/generate/slides, /generate/image, /render, /stores/:id/sync
Mutating120 / minuteAll POST / PATCH / DELETE writes
Read600 / minuteAll GET requests
Exceeding a limit returns a 429 response with a Retry-After header indicating when to retry:
{
  "success": false,
  "message": "Rate limit exceeded for expensive endpoints. Retry in 60s."
}
Rate limits are enforced by Cloudflare’s native rate-limiting API. Counters reset every 60 seconds.