Applies to: API v1
This page consolidates foundational API concepts for quick reference: error triage, capability mapping, rate limiting, and versioning policy.
Use this matrix to triage API failures quickly and choose the next action.
| Status | Meaning | Common causes | First action |
|---|---|---|---|
401 Unauthorized |
Authentication failed | Missing/invalid Bearer token, invalid client credentials, expired token | Re-issue token and verify Authorization: Bearer <token> |
403 Forbidden |
Authenticated but not allowed | Policy/capability mismatch for request path | Check policy path + required capability mapping |
404 Not Found |
Route/resource missing | Wrong endpoint shape, unknown resource ID/key/path | Verify endpoint path shape first, then resource existence |
409 Conflict |
Resource state conflict | Duplicate create (for example existing transit key name) | Switch to rotate/update flow or use unique resource name |
422 Unprocessable Entity |
Validation failed | Invalid JSON/body/query, bad base64, malformed ciphertext contract | Validate payload and endpoint-specific contract |
429 Too Many Requests |
Request throttled | Per-client or per-IP rate limit exceeded | Respect Retry-After and retry with backoff + jitter |
- Check status code class (
401/403/404/409/422/429) - Validate route shape (to avoid misreading
404as policy issue) - Validate token/authn (
401) before policy/authz (403) - Validate payload contract (
422) using endpoint docs - For
429, apply retry policy and reassess client concurrency
401 Unauthorized: authentication failed before policy check; verify token or client credentials first403 Forbidden: authentication succeeded, but policy/capability denied requested path429 Too Many Requests: request hit per-client or per-IP throttling; inspectRetry-After
First place to look:
401: token issuance/authentication logs and credential validity403: policy document, capability mapping, and path matcher behavior429: rate-limit settings (RATE_LIMIT_*,RATE_LIMIT_TOKEN_*) and traffic burst patterns
POST /v1/clientsrequireswriteGET /v1/clientsrequiresreadGET /v1/clients/:idrequiresreadPUT /v1/clients/:idrequireswriteDELETE /v1/clients/:idrequiresdeletePOST /v1/clients/:id/unlockrequireswriteGET /v1/secretsrequiresreadGET /v1/secrets/*pathrequiresdecryptPOST /v1/secrets/*pathrequiresencryptDELETE /v1/secrets/*pathrequiresdeleteGET /v1/transit/keysrequiresreadPOST /v1/transit/keysrequireswritePOST /v1/transit/keys/:name/rotaterequiresrotateDELETE /v1/transit/keys/:namerequiresdeletePOST /v1/transit/keys/:name/encryptrequiresencryptPOST /v1/transit/keys/:name/decryptrequiresdecryptGET /v1/tokenization/keysrequiresreadPOST /v1/tokenization/keysrequireswritePOST /v1/tokenization/keys/:name/rotaterequiresrotateDELETE /v1/tokenization/keys/:idrequiresdeletePOST /v1/tokenization/keys/:name/tokenizerequiresencryptPOST /v1/tokenization/detokenizerequiresdecryptPOST /v1/tokenization/validaterequiresreadPOST /v1/tokenization/revokerequiresdeleteGET /v1/audit-logsrequiresread
This section is the canonical capability-to-endpoint reference used by API docs and policy templates.
read: list or inspect metadata/state without decrypting payload valueswrite: create or update non-cryptographic resources and key definitionsdelete: delete resources or revoke token lifecycle entriesencrypt: create encrypted outputs (secrets writes, transit encrypt, tokenization tokenize)decrypt: resolve encrypted/tokenized values back to plaintextrotate: create new key versions
| Endpoint | Required capability |
|---|---|
POST /v1/clients |
write |
GET /v1/clients |
read |
GET /v1/clients/:id |
read |
PUT /v1/clients/:id |
write |
DELETE /v1/clients/:id |
delete |
POST /v1/clients/:id/unlock |
write |
GET /v1/audit-logs |
read |
POST /v1/secrets/*path |
encrypt |
GET /v1/secrets |
read |
GET /v1/secrets/*path |
decrypt |
DELETE /v1/secrets/*path |
delete |
GET /v1/transit/keys |
read |
POST /v1/transit/keys |
write |
POST /v1/transit/keys/:name/rotate |
rotate |
DELETE /v1/transit/keys/:name |
delete |
POST /v1/transit/keys/:name/encrypt |
encrypt |
POST /v1/transit/keys/:name/decrypt |
decrypt |
GET /v1/tokenization/keys |
read |
POST /v1/tokenization/keys |
write |
POST /v1/tokenization/keys/:name/rotate |
rotate |
DELETE /v1/tokenization/keys/:id |
delete |
POST /v1/tokenization/keys/:name/tokenize |
encrypt |
POST /v1/tokenization/detokenize |
decrypt |
POST /v1/tokenization/validate |
read |
POST /v1/tokenization/revoke |
delete |
Policy matcher quick reference:
| Pattern type | Example | Matching behavior |
|---|---|---|
| Exact | /v1/audit-logs |
Only that exact path |
| Full wildcard | * |
Any request path |
| Trailing wildcard | /v1/secrets/* |
Prefix + nested paths |
| Mid-path wildcard | /v1/transit/keys/*/rotate |
* matches one segment |
For complete matcher semantics and unsupported forms, see Policies cookbook.
See ADR 0003: Capability-Based Authorization Model for the architectural rationale behind this design.
- Use path scope as narrowly as possible (service + environment prefixes).
- Avoid wildcard
*except temporary break-glass workflows. - Keep encrypt and decrypt separated across clients when operationally possible.
- For tokenization lifecycle endpoints, token value is passed in JSON body; policy path is endpoint path.
Secrets enforces two rate-limiting scopes:
- Per-client limits for authenticated API routes (
RATE_LIMIT_*) - Per-IP limits for unauthenticated token issuance (
RATE_LIMIT_TOKEN_*)
See ADR 0006: Dual-Scope Rate Limiting Strategy for the architectural rationale behind this design.
Rate limiting scope matrix:
| Route group/endpoint | Rate limited | Notes |
|---|---|---|
/v1/clients/* |
Yes | Requires Bearer auth |
/v1/audit-logs |
Yes | Requires Bearer auth |
/v1/secrets/* |
Yes | Requires Bearer auth |
/v1/transit/* |
Yes | Requires Bearer auth |
/v1/tokenization/* |
Yes | Requires Bearer auth |
POST /v1/token |
Yes | Unauthenticated endpoint, rate-limited per client IP |
GET /health |
No | Liveness checks |
GET /ready |
No | Readiness checks |
GET :8081/metrics |
No | Prometheus scraping |
# Authenticated endpoints (per client)
RATE_LIMIT_ENABLED=true
RATE_LIMIT_REQUESTS_PER_SEC=10.0
RATE_LIMIT_BURST=20
# Token endpoint (per IP)
RATE_LIMIT_TOKEN_ENABLED=true
RATE_LIMIT_TOKEN_REQUESTS_PER_SEC=5.0
RATE_LIMIT_TOKEN_BURST=10When a request exceeds the allowed rate, the API returns:
- Status:
429 Too Many Requests - Header:
Retry-After: <seconds> - Body:
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please retry after the specified delay."
}Token endpoint (POST /v1/token) uses the same status/header contract and returns an endpoint-specific
message indicating too many token requests from the caller IP.
- Respect
Retry-Afterbefore retrying - Use exponential backoff with jitter
- Avoid synchronized retries across many workers
- Reduce per-client burst and concurrency where possible
- For token issuance, review shared NAT/proxy behavior and tune
RATE_LIMIT_TOKEN_*if needed
403 Forbidden: policy/capability denies access429 Too Many Requests: request was throttled by per-client or per-IP rate limits
This section defines compatibility expectations for HTTP API changes.
Warning
While in versions v0.x.y, the API is not yet stable and is subject to many changes.
See ADR 0007: Path-Based API Versioning for the architectural rationale behind this design.
- Current public baseline is API v1 (
/v1/*) - Existing endpoint paths and JSON field names are treated as stable unless explicitly deprecated
- OpenAPI source of truth:
docs/openapi.yaml
docs/openapi.yamlis a baseline subset focused on high-traffic/common integration flowsdocs/openapi.yamlincludes tokenization endpoint coverage in the current releasedocs/openapi.yamlincludes429 Too Many Requestsresponse modeling for protected routes- Endpoint pages in
docs/api/*.mddefine full public behavior for covered operations - Endpoints may exist in runtime before they are expanded in OpenAPI detail
- Application release is pre-1.0 software and may evolve quickly
- API v1 path contract (
/v1/*) remains the compatibility baseline for consumers - Breaking API behavior changes require explicit documentation and migration notes
Treat these as breaking:
- changing endpoint paths or required path parameters
- removing response fields or changing field meaning/type
- changing required request fields or accepted formats
- changing status code semantics for successful behavior
Required process for breaking changes:
- Update
docs/openapi.yaml - Update affected API docs and examples
- Add migration notes in
docs/operations/troubleshooting/index.mdor relevant runbook - Add explicit entry in
CHANGELOG.md
Usually non-breaking:
- adding optional request/response fields
- adding new endpoints under
/v1/* - clarifying documentation text and examples
- adding additional error examples without changing behavior
Breaking telemetry examples:
- renaming a published metric name (for example
secrets_http_requests_total) - renaming/removing metric labels used by dashboards or alerts
Non-breaking telemetry examples:
- adding a new metric family
- adding new label values for existing labels
- adding new dashboard examples without changing metric contracts
- Mark deprecated behavior clearly in endpoint docs
- Provide replacement behavior and example migration path
- Keep deprecated behavior available long enough for operational rollout