Contents
- REST API
- Errors
- Endpoints
- POST /v1/secrets — create (admin)
- GET /v1/secrets/{name} — read current value (reader, IP-allowlisted)
- GET /v1/secrets — list metadata (admin)
- PUT /v1/secrets/{name} — update (admin)
- DELETE /v1/secrets/{name} — delete (admin)
- POST /v1/secrets/{name}/rotate — rotate now (admin)
- POST /v1/secrets/{name}/verify — validate a presented value (reader, IP-allowlisted)
- GET /healthz / GET /readyz
REST API
Base URL: http://<node>:8200. All bodies are JSON.
- Reads (
GET /v1/secrets/{name},POST /v1/secrets/{name}/verify) require the client IP to be inVAULT_ALLOWED_IPS. - Management (
POST/PUT/DELETE /v1/secrets,/rotate) requiresAuthorization: Bearer <admin-token>.
Errors
{ "error": "<message>" } with status 400 (bad request), 401
(unauthorized), 403 (IP not allowed), 404 (not found), 409 (name
conflict), 500 (internal — detail is logged, not returned).
Endpoints
POST /v1/secrets — create (admin)
{
"name": "db/password",
"kind": "manual",
"value": "s3cr3t",
"description": "primary db password"
}
Automatic secret (value optional; generated if omitted):
{
"name": "svc/api-key",
"kind": "automatic",
"rotation_interval_secs": 86400,
"grace_period_secs": 3600
}
201 Created →
{ "name": "svc/api-key", "kind": "automatic", "version": 1, "value": "f3q...", "created_at": "2026-06-13T12:00:00+00:00" }
GET /v1/secrets/{name} — read current value (reader, IP-allowlisted)
{ "name": "db/password", "kind": "manual", "version": 1, "value": "s3cr3t", "created_at": "..." }
GET /v1/secrets — list metadata (admin)
Returns metadata only (no plaintext) for every secret.
PUT /v1/secrets/{name} — update (admin)
Any field optional. Supplying value creates a new version; the previous
version is kept valid for grace_period.
{ "value": "n3w-s3cr3t", "description": "rotated manually" }
Returns the updated metadata.
DELETE /v1/secrets/{name} — delete (admin)
204 No Content. Cascades to all versions and pending jobs.
POST /v1/secrets/{name}/rotate — rotate now (admin)
Valid for automatic secrets only (manual secrets are changed via PUT).
Generates a new version, supersedes the old one with a grace window, and resets
next_rotation_at. Returns the new SecretValue.
POST /v1/secrets/{name}/verify — validate a presented value (reader, IP-allowlisted)
{ "value": "f3q..." }
→
{ "valid": true, "version": 2 }
Checks the presented value (constant-time) against every currently-valid version — the current one plus any superseded version still inside its grace window. This is how a dependent service confirms an old automatic secret is still accepted during rotation.
GET /healthz / GET /readyz
Liveness (ok) and readiness (ready, checks a DB connection).