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

# Authentication

> Bearer API keys, rotation, IP allowlisting, and rate limits.

Every request to `/v1` authenticates with an API key Jenzy issues at
onboarding, sent as a bearer token:

```bash theme={null}
curl https://api.jenzy.com/v1/ping \
  -H "Authorization: Bearer jz_live_AbC123XyZ..."
```

## Keys

* Keys are opaque: `jz_live_` followed by a long random body. Only the first
  16 characters (the **prefix**, e.g. `jz_live_AbC123Xy`) ever appear again —
  in your portal, in audit trails, in support conversations. Refer to keys by
  prefix when talking to Jenzy.
* **The full key is shown exactly once, at issuance.** It cannot be
  recovered — store it in your secrets manager immediately. A lost key means
  rotating to a new one.
* `jz_test_` keys exist in the format but are not issued during the pilot —
  every key is live. See [Testing your integration](/testing).

<Warning>
  Treat your key like money: it can spend your balance. Never put it in
  client-side code, logs, or URLs. If you suspect a leak, contact Jenzy
  immediately to revoke it — revocation is instant.
</Warning>

## Rotation

Rotation is overlap, not an event: your org can hold several active keys.
Ask Jenzy to issue a new key, switch your systems over, then have the old one
revoked. At no point are you keyless, so there is no downtime window to
schedule.

## IP allowlisting (optional)

An org admin can restrict your key to an exact list of IPs in the Jenzy
portal (Integration settings). With a non-empty allowlist, requests from any
other address get `403 forbidden` — the key alone is no longer enough.
Entries are exact IPv4/IPv6 addresses (no CIDR ranges). The allowlist is
managed by portal session only, never by API key: a leaked key cannot widen
its own allowlist.

## Rate limits

Requests are rate-limited per org. Over the limit you get:

```json theme={null}
{ "error": { "code": "rate_limited", "message": "rate limit exceeded" } }
```

with HTTP `429` and a `Retry-After` header (seconds). Honor it and back off —
polling `GET /balance` and `GET /payouts/{id}` at a modest cadence stays
comfortably under the limit. Note `org_limit_exceeded` is different: that's a
payout-creation velocity/daily cap, not a request rate — see
[Errors](/errors).
