Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Batch Operations

Read or update many secrets in a single request. Useful when an application needs several credentials at startup, or when a config loader wants a whole subtree at once.

Base path: /v1/secrets/batch/

Batch read#

bash
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
curl -X POST https://scaivault.scailabs.ai/v1/secrets/batch \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "paths": [
      "integrations/salesforce/oauth",
      "integrations/scaisend/api-key",
      "integrations/stripe/secret-key"
    ],
    "options": {
      "include_metadata": false,
      "fail_fast": false
    }
  }'
python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
paths = [
    "integrations/salesforce/oauth",
    "integrations/scaisend/api-key",
    "integrations/stripe/secret-key",
]
resp = httpx.post(
    "https://scaivault.scailabs.ai/v1/secrets/batch",
    headers={"Authorization": f"Bearer {os.environ['SCAIVAULT_TOKEN']}"},
    json={"paths": paths},
)
result = resp.json()
for path, secret in result["secrets"].items():
    print(path, secret["version"])
typescript
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
const resp = await fetch("https://scaivault.scailabs.ai/v1/secrets/batch", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SCAIVAULT_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    paths: [
      "integrations/salesforce/oauth",
      "integrations/scaisend/api-key",
    ],
  }),
});
const result = await resp.json();

Response:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
  "secrets": {
    "integrations/salesforce/oauth": {
      "data": {"client_id": "...", "client_secret": "..."},
      "version": 3,
      "secret_type": "json"
    },
    "integrations/scaisend/api-key": {
      "data": {"key": "sk_send_..."},
      "version": 1,
      "secret_type": "api_key"
    }
  },
  "errors": {
    "integrations/stripe/secret-key": {
      "code": "access_denied",
      "message": "No policy permits read on this path"
    }
  },
  "retrieved": 2,
  "failed": 1
}

Partial success is the default behavior — missing or denied paths show up in errors, everything else is in secrets. Pass "fail_fast": true to abort the whole batch on first error.

Options#

Option Description
include_metadata Include full metadata in each result (default: false)
fail_fast Abort on first error (default: false)
version Read all paths at a specific version. Useful for coordinated config snapshots.

Limits#

  • Maximum 100 paths per request.
  • Each path is evaluated against policies individually — a batch doesn't bypass access control.
  • A batch read counts as 1 call against the batch-read rate limit and N calls against the read rate limit (where N is the number of paths successfully returned).

Batch metadata#

Like batch read, but returns metadata only — no values. Policies still apply, but secrets:list is sufficient; full secrets:read is not required.

bash
1
2
3
4
5
6
7
curl -X POST https://scaivault.scailabs.ai/v1/secrets/batch/metadata \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "paths": ["integrations/salesforce/*", "integrations/stripe/*"],
    "expand_wildcards": true
  }'

With expand_wildcards: true, path patterns are expanded server-side to the actual matching paths.

Response:

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
  "metadata": {
    "integrations/salesforce/oauth": {
      "version": 3,
      "updated_at": "2026-04-20T...",
      "tags": ["salesforce", "production"]
    },
    "integrations/salesforce/webhook-secret": {
      "version": 1,
      "updated_at": "2026-02-10T..."
    }
  }
}

Batch write#

Not supported. Writes are explicitly one-at-a-time. Two reasons:

  1. Atomicity. Batch writes imply "all or nothing" — ScaiVault has no distributed transaction to make that guarantee cleanly across versioning, policies, and audit.
  2. Auditability. Per-write audit entries make it obvious who wrote what when. A single batch entry hides what changed.

If you need to seed many secrets, loop over PUT /v1/secrets/{path}. The rate limits allow bursts of ~100/min per identity.

Startup pattern#

A service that needs N secrets at startup:

python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import os, httpx

CREDENTIALS_TO_LOAD = [
    "integrations/salesforce/oauth",
    "integrations/scaisend/api-key",
    "integrations/stripe/secret-key",
    "infra/db/primary/credentials",
    "infra/redis/primary/credentials",
]

def load_all_credentials():
    resp = httpx.post(
        "https://scaivault.scailabs.ai/v1/secrets/batch",
        headers={"Authorization": f"Bearer {os.environ['SCAIVAULT_TOKEN']}"},
        json={"paths": CREDENTIALS_TO_LOAD, "options": {"fail_fast": True}},
        timeout=10.0,
    )
    resp.raise_for_status()
    return resp.json()["secrets"]

secrets = load_all_credentials()

With fail_fast: true, any missing or denied secret fails the service startup loudly — which is what you want in this situation. A service that starts partially healthy is worse than one that fails to start.

When to use batch vs individual reads#

Use batch Use individual
Known fixed set of paths loaded together Paths discovered at runtime
Startup / config loading Per-request lookups (with cache)
Inventory and dashboards (metadata variant) Long-lived connections with rotation subscription

Batch isn't always faster — ScaiVault validates each path against policies and fetches each from storage. For a single path, the overhead is indistinguishable from a direct GET.

What's next#

Updated 2026-05-17 13:26:50 View source (.md) rev 2