Managing Secrets
Read, write, version, delete, and list secrets. The day-to-day work of using ScaiVault.
Base path: /v1/secrets/
For the conceptual model, see Secrets. For endpoint reference, see Secrets Reference.
Read a secret
| curl -H "Authorization: Bearer $TOKEN" \
https://scaivault.scailabs.ai/v1/secrets/environments/production/salesforce/api-credentials
|
| import os, httpx
resp = httpx.get(
"https://scaivault.scailabs.ai/v1/secrets/environments/production/salesforce/api-credentials",
headers={"Authorization": f"Bearer {os.environ['SCAIVAULT_TOKEN']}"},
)
resp.raise_for_status()
secret = resp.json()
print(secret["data"]["client_id"])
|
| const resp = await fetch(
"https://scaivault.scailabs.ai/v1/secrets/environments/production/salesforce/api-credentials",
{ headers: { "Authorization": `Bearer ${process.env.SCAIVAULT_TOKEN}` } },
);
const secret = await resp.json();
console.log(secret.data.client_id);
|
Read a specific version:
| curl -H "Authorization: Bearer $TOKEN" \
"https://scaivault.scailabs.ai/v1/secrets/environments/production/salesforce/api-credentials?version=2"
|
Write a secret
Writing creates a new version (or the first version).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | curl -X PUT https://scaivault.scailabs.ai/v1/secrets/environments/production/salesforce/api-credentials \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"data": {
"client_id": "3MVG9...",
"client_secret": "REDACTED"
},
"secret_type": "json",
"metadata": {
"description": "Salesforce OAuth credentials",
"tags": ["salesforce", "oauth", "production"]
},
"options": {
"max_versions": 10,
"expires_in": "90d",
"rotation_policy_id": "rot_quarterly"
}
}'
|
| resp = httpx.put(
"https://scaivault.scailabs.ai/v1/secrets/environments/production/salesforce/api-credentials",
headers={"Authorization": f"Bearer {os.environ['SCAIVAULT_TOKEN']}"},
json={
"data": {"client_id": "3MVG9...", "client_secret": "REDACTED"},
"secret_type": "json",
"metadata": {"tags": ["salesforce", "production"]},
"options": {"max_versions": 10},
},
)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | const resp = await fetch(
"https://scaivault.scailabs.ai/v1/secrets/environments/production/salesforce/api-credentials",
{
method: "PUT",
headers: {
"Authorization": `Bearer ${process.env.SCAIVAULT_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
data: { client_id: "3MVG9...", client_secret: "REDACTED" },
secret_type: "json",
metadata: { tags: ["salesforce", "production"] },
options: { max_versions: 10 },
}),
},
);
|
Response for a new secret (201 Created):
| {
"path": "environments/production/salesforce/api-credentials",
"secret_type": "json",
"version": 1,
"created": true,
"created_at": "2026-04-23T14:00:00Z",
"expires_at": "2026-07-22T14:00:00Z"
}
|
For an update (200 OK):
| {
"path": "environments/production/salesforce/api-credentials",
"version": 4,
"created": false,
"previous_version": 3,
"updated_at": "2026-04-23T14:00:00Z"
}
|
Write fields
| Field |
Type |
Required |
Description |
data |
object |
Yes |
The secret payload |
secret_type |
string |
No |
kv (default), json, certificate, ssh_key, api_key |
metadata |
object |
No |
Non-secret metadata |
metadata.description |
string |
No |
Human-readable description |
metadata.tags |
array of string |
No |
Searchable tags |
metadata.owner |
string |
No |
Owner identity (team, user, group) |
options |
object |
No |
Secret-level settings |
options.max_versions |
integer (1–100) |
No |
Version retention cap |
options.expires_in |
duration |
No |
Relative expiration (90d, 24h) |
options.expires_at |
ISO 8601 |
No |
Absolute expiration |
options.rotation_policy_id |
string |
No |
Attach a rotation policy |
options.secret_policy_id |
string |
No |
Attach a value-generation policy |
| curl -X PATCH https://scaivault.scailabs.ai/v1/secrets/app/db/password \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"metadata": {
"tags": ["postgres", "production", "critical"]
},
"options": {"max_versions": 25}
}'
|
Returns updated metadata. Does not create a new version or invalidate caches.
List secrets
| curl -H "Authorization: Bearer $TOKEN" \
"https://scaivault.scailabs.ai/v1/secrets?prefix=environments/production/&limit=50"
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | resp = httpx.get(
"https://scaivault.scailabs.ai/v1/secrets",
headers={"Authorization": f"Bearer {os.environ['SCAIVAULT_TOKEN']}"},
params={"prefix": "environments/production/", "limit": 50},
)
listing = resp.json()
for s in listing["secrets"]:
print(s["path"], s["version"])
# Paginate
while listing["has_more"]:
resp = httpx.get(
"https://scaivault.scailabs.ai/v1/secrets",
headers={"Authorization": f"Bearer {os.environ['SCAIVAULT_TOKEN']}"},
params={"prefix": "environments/production/", "cursor": listing["cursor"]},
)
listing = resp.json()
|
| const params = new URLSearchParams({ prefix: "environments/production/", limit: "50" });
const resp = await fetch(
`https://scaivault.scailabs.ai/v1/secrets?${params}`,
{ headers: { "Authorization": `Bearer ${process.env.SCAIVAULT_TOKEN}` } },
);
const listing = await resp.json();
for (const s of listing.secrets) console.log(s.path, s.version);
|
Response:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | {
"secrets": [
{
"path": "environments/production/salesforce/api-credentials",
"secret_type": "json",
"version": 3,
"updated_at": "2026-04-20T14:22:00Z",
"expires_at": null,
"tags": ["salesforce", "oauth"]
}
],
"cursor": "eyJpZCI6MTc4fQ",
"has_more": true,
"total_count": 127
}
|
List filters
| Parameter |
Description |
prefix |
Path prefix |
tag |
Tag (repeatable) |
secret_type |
kv, json, etc. |
expires_before |
ISO timestamp |
updated_after |
ISO timestamp |
include_expired |
Include secrets past expires_at |
include_metadata |
Return full metadata (default: minimal) |
limit |
Max per page (default 50, max 200) |
cursor |
Next-page cursor |
List secret versions
| curl -H "Authorization: Bearer $TOKEN" \
https://scaivault.scailabs.ai/v1/secrets/app/db/password/versions
|
| {
"path": "app/db/password",
"versions": [
{"version": 3, "created_at": "2026-04-20T...", "is_current": true},
{"version": 2, "created_at": "2026-03-15T...", "is_current": false},
{"version": 1, "created_at": "2026-01-01T...", "is_current": false}
]
}
|
Useful when you want version number, tags, rotation status without reading the value — e.g., for inventory or dashboards.
| curl -H "Authorization: Bearer $TOKEN" \
https://scaivault.scailabs.ai/v1/secrets/metadata/app/db/password
|
Response:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | {
"path": "app/db/password",
"current_version": 3,
"version_count": 3,
"metadata": {
"description": "PostgreSQL production password",
"tags": ["postgres", "production"]
},
"created_at": "2026-01-01T12:00:00Z",
"updated_at": "2026-04-20T14:22:00Z",
"last_accessed_at": "2026-04-23T10:15:00Z",
"access_count_30d": 1547,
"rotation_policy": {
"id": "rot_quarterly",
"next_rotation": "2026-07-20T00:00:00Z"
}
}
|
Delete a secret
Soft delete (recoverable for 30 days by default):
| curl -X DELETE https://scaivault.scailabs.ai/v1/secrets/app/db/password \
-H "Authorization: Bearer $TOKEN"
|
Hard delete (permanent, requires admin):
| curl -X DELETE "https://scaivault.scailabs.ai/v1/secrets/app/db/password?permanent=true" \
-H "Authorization: Bearer $TOKEN"
|
Delete only a specific version:
| curl -X DELETE "https://scaivault.scailabs.ai/v1/secrets/app/db/password?version=2" \
-H "Authorization: Bearer $TOKEN"
|
Restore a soft-deleted secret:
| curl -X POST https://scaivault.scailabs.ai/v1/secrets/app/db/password/restore \
-H "Authorization: Bearer $TOKEN"
|
Rotate a secret
Triggers immediate rotation. If the secret has a rotation policy attached and auto_generate: true, ScaiVault generates the new value. Otherwise, supply new_value.
| curl -X POST https://scaivault.scailabs.ai/v1/secrets/app/db/password/rotate \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"reason": "Suspected compromise",
"new_value": {"password": "new-strong-password"},
"grace_period": "1h"
}'
|
Returns the new version. Old version stays readable for the grace period.
Find expiring secrets
| curl -H "Authorization: Bearer $TOKEN" \
"https://scaivault.scailabs.ai/v1/secrets/expiring?days=30"
|
| {
"secrets": [
{
"path": "test/oauth-token",
"expires_at": "2026-05-02T00:00:00Z",
"days_remaining": 9
}
]
}
|
Partner-scoped secrets
Write shared values visible to every tenant under the partner:
| curl -X PUT https://scaivault.scailabs.ai/v1/partner/secrets/shared/trust-anchor \
-H "Authorization: Bearer $PARTNER_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"data": {"cert_pem": "..."}, "secret_type": "certificate"}'
|
Every tenant reads with GET /v1/partner/secrets/shared/trust-anchor. Only partner admins can write.
Cross-tenant access
Partner admins can act as a specific tenant by prefixing /v1/t/{tenant_id}/:
| curl -H "Authorization: Bearer $PARTNER_ADMIN_TOKEN" \
https://scaivault.scailabs.ai/v1/t/tnt_acme_dev/secrets/app/db/password
|
All audit log entries record both the acting identity and the target tenant.
Common error codes
| Code |
When |
secret_not_found |
Path doesn't exist in this tenant |
secret_exists |
Soft-deleted path in retention window |
version_not_found |
Version aged out or doesn't exist |
invalid_path |
Path format violation |
version_conflict |
Concurrent write; refetch and retry |
access_denied |
No policy permits this action |
secret_expired |
expires_at has passed |
What's next