Secrets Vault
Encrypted, versioned secret storage for per-organization credentials and config values.
All endpoints require Authorization: Bearer <jwt>. Write operations additionally require the vault:write scope.
Endpoints
PUT /api/admin/organizations/:org_uuid/secrets/:name
Creates or updates a secret. Secrets are versioned; each write creates a new version.
Input: ~~~json { "value": "sk_live_abc123...", "description": "Stripe live key", "tags": ["billing", "stripe"] } ~~~
Output: ~~~json { "name": "stripe_secret_key", "version": 3, "created_at": "2024-07-11T10:00:00Z" } ~~~
GET /api/admin/organizations/:org_uuid/secrets/:name
Retrieves the latest version of a secret.
Output: ~~~json { "name": "stripe_secret_key", "value": "sk_live_abc123...", "version": 3, "created_at": "2024-07-11T10:00:00Z", "tags": ["billing", "stripe"] } ~~~
GET /api/admin/organizations/:org_uuid/secrets/:name/versions
Lists all versions of a secret (values are not returned).
Output: ~~~json { "versions": [ { "version": 3, "created_at": "2024-07-11T10:00:00Z" }, { "version": 2, "created_at": "2024-06-01T00:00:00Z" }, { "version": 1, "created_at": "2024-05-01T00:00:00Z" } ] } ~~~
GET /api/admin/organizations/:org_uuid/secrets/:name/versions/:version
Retrieves a specific version of a secret.
DELETE /api/admin/organizations/:org_uuid/secrets/:name
Soft-deletes a secret (all versions). The secret can be restored within 30 days.
GET /api/admin/organizations/:org_uuid/secrets
Lists all secret names (not values) for the organization.
Output: ~~~json { "data": [ { "name": "stripe_secret_key", "version": 3, "tags": ["billing"] }, { "name": "sendgrid_api_key", "version": 1, "tags": ["email"] } ] } ~~~
Encryption
All secret values are encrypted at rest using AES-256-GCM with per-organization encryption keys stored in ButtrBase's HSM.
Audit Log
Every read and write operation on the vault is logged to the organization's audit trail.
SDK Examples
Python
~~~python client.put_secret_admin("org-uuid", "stripe_secret_key", "sk_live_abc123...") secret = client.get_secret_by_name("org-uuid", "stripe_secret_key") secrets = client.list_secrets("org-uuid") client.delete_secret("org-uuid", "stripe_secret_key") ~~~
Node.js / TypeScript
~~~typescript await client.putSecret('org-uuid', 'stripe_secret_key', 'sk_live_abc123...'); const secret = await client.getSecret('org-uuid', 'stripe_secret_key'); const secrets = await client.listSecrets('org-uuid'); await client.deleteSecret('org-uuid', 'stripe_secret_key'); ~~~
Go
~~~go _, err := client.PutSecret(ctx, "org-uuid", "stripe_secret_key", "sk_live_abc123...", "Stripe key") secret, err := client.GetSecret(ctx, "org-uuid", "stripe_secret_key") secrets, err := client.ListSecrets(ctx, "org-uuid") ~~~
Rust
~~~rust client.put_secret("org-uuid", "stripe_secret_key", "sk_live_abc123...").await?; let secret = client.get_secret("org-uuid", "stripe_secret_key").await?; let secrets = client.list_secrets("org-uuid").await?; client.delete_secret("org-uuid", "stripe_secret_key").await?; ~~~
Endpoint Summary
| Method | Path | Purpose |
|---|---|---|
| PUT | /api/admin/organizations/{org}/secrets/{name} | Create / update secret |
| GET | /api/admin/organizations/{org}/secrets/{name} | Get latest version |
| GET | /api/admin/organizations/{org}/secrets/{name}/versions | List versions |
| GET | /api/admin/organizations/{org}/secrets/{name}/versions/{v} | Get specific version |
| DELETE | /api/admin/organizations/{org}/secrets/{name} | Soft-delete secret |
| GET | /api/admin/organizations/{org}/secrets | List all secrets |
When to Use
- Storing third-party API keys per customer service
- Rotate a key in one place and let workers pick up within 5 minutes
Error Reference
| Status | Code | Meaning |
|--------|------|---------|
| 400 | validation_error | Secret name or value failed validation |
| 401 | unauthorized | Missing or invalid Authorization header |
| 403 | forbidden | Insufficient vault access scope |
| 404 | secret_not_found | Secret path does not exist |
| 409 | version_conflict | Concurrent write detected; retry with latest version |
| 423 | vault_sealed | Vault is sealed; requires operator unseal |