Authorization header:
| Use case | Token type | Lifetime |
|---|---|---|
| Server-to-server (your backend, CI, scripts) | API key (kyn_live_... / kyn_test_...) | Long-lived — until rotated |
| End-user request from your frontend | JWT (issued by your auth provider) | Short — minutes |
Method 1 — API key (Bearer)
API keys live in Settings → API Keys. Each key has:| Field | Notes |
|---|---|
| Prefix | kyn_live_ (charges credits) or kyn_test_ (free, sandbox). Legacy rf_live_ / rf_test_ keys remain valid. |
| Scopes | What the key can do (render:write, brands:read, etc.). Scope down whenever possible. |
| Created / Last used | Visible in the dashboard. Use this to find stale keys. |
Send the key
Rotate a key
- In the dashboard, click Rotate on the key you want to replace.
- The new key is shown once. Update your secrets store immediately.
- The old key keeps working for a 24-hour grace window. After that it returns
UNAUTHORIZED.
Store keys safely
- Backend: load from your secret manager (AWS Secrets Manager, GCP Secret Manager, Doppler, 1Password Connect). Never commit to git.
- Local dev: use a
.envfile ignored by git, or your shell’s keychain. - CI: provision as a masked secret in GitHub Actions / GitLab CI / etc.
Method 2 — JWT (end-user, short-lived)
If your product makes Kynva calls on behalf of an end user (e.g., a browser app where the user pays per render), use JWTs instead of API keys.How it works
- Configure your JWT issuer in Settings → Auth — issuer URL + JWKS endpoint.
- Your backend mints a JWT for the requesting user. Include:
sub— the user’s stable ID in your systemaud: "kynva"exp— short. 5–15 minutes is typical.
- Pass the JWT as the bearer token.
Send the JWT
JWT requirements
| Claim | Required | Notes |
|---|---|---|
iss | yes | Must match the issuer URL configured in your workspace. |
aud | yes | Must be kynva. |
sub | yes | Stable user identifier. Used for usage attribution and rate limits. |
exp | yes | Must be in the future and within 24h of iat. We recommend ≤ 15 min. |
iat | recommended | Issued-at timestamp. |
nbf | optional | If set, must be ≤ now. |
UNAUTHORIZED.
Verifying a request succeeded
A successful authenticated request includes:Frequently asked
My legacy rf_live_ key — do I need to migrate?
My legacy rf_live_ key — do I need to migrate?
No. Legacy
rf_* keys keep working indefinitely. New keys are issued with the kyn_ prefix. Nothing about the wire protocol changed.Can I scope a key to a single brand?
Can I scope a key to a single brand?
Yes. In the dashboard, edit a key and add
brand:brand_abc to its scope. The key will return FORBIDDEN if used against any other brand.Do test keys (kyn_test_) talk to the same backend?
Do test keys (kyn_test_) talk to the same backend?
Yes. Same backend, same code, but renders made with a test key are watermarked and don’t consume credits.
What's the rate limit per key vs per workspace?
What's the rate limit per key vs per workspace?
Limits apply per workspace, not per key. See Rate limits for the per-category caps.