POST /api/zsc/probe-permission
Run a permission gate check against ZeqContext.read() as if the
supplied ZID were calling. Returns the boolean outcome plus a reason
code, without exposing the plaintext.
This is the operator's "can ZID-X read secret STRIPE_SECRET_KEY?"
question, answered safely. Every probe still emits an audit row
(secret_read for granted, secret_denied for the three failure
reasons) so probes are forensically tracked alongside real reads.
Auth
Admin cookie (zeq_admin) required.
Request
curl -H "Cookie: zeq_admin=$ADMIN_JWT" \
-H "Content-Type: application/json" \
-X POST https://YOUR-FRAMEWORK/api/zsc/probe-permission \
-d '{
"name": "STRIPE_SECRET_KEY",
"asZid": "ZEQ07111111111",
"purpose": "ops_audit"
}'
Body fields
| Field | Required | Type | Notes |
|---|---|---|---|
name | yes | string | The vault key. |
asZid | yes | string | The ZID to probe as. |
purpose | no | string | Audit-row purpose label. Default: "probe_check". |
Response · 200 OK — granted
{ "ok": true, "granted": true }
The probe ZID would successfully read this secret today.
Response · 200 OK — denied
{ "ok": true, "granted": false, "reason": "denied" }
Probe ZID is not in bound_zid, permissions[], or ZEQ-SYS.
Response · 200 OK — rate-limited
{ "ok": true, "granted": false, "reason": "rate_limited" }
Probe ZID has hit 5+ denials in the last 60 Zeqonds and is now in the denial window. Limiter clears when the window expires.
Response · 200 OK — not found
{ "ok": true, "granted": false, "reason": "not_found" }
No row exists with this name. The probe still works (returns
quickly without DB hits beyond the missing lookup) so you can use it
as a "does this secret exist?" check that's safe to expose to less-
privileged ops scripts.
Response · 200 OK — unexpected error
{ "ok": true, "granted": false, "reason": "error", "detail": "<message>" }
Caught a non-expected throw from the read path. Check api-core logs. This shouldn't happen in normal operation — file an incident if it does.
Errors (HTTP 4xx / 5xx)
| Status | error | Cause |
|---|---|---|
400 | name required | Empty/missing name. |
400 | asZid required | Empty/missing asZid. |
401 | unauthorized | Admin cookie missing/invalid. |
500 | INTERNAL_ERROR | Outer error — probe machinery itself failed. |
Audit row impact
Probes are real reads through ZeqContext.read() — they consume the
same audit row budget. A probe that returns granted: true emits a
secret_read. The four granted: false reasons emit secret_denied
with the matching reason in payload_json.
Repeated probes against the same (name, asZid) count toward the
rate-limit window. Don't loop-probe — it'll trip the limiter and
deny legitimate reads from the same ZID.
Related
POST /api/zsc/grant/:name— fix adeniedoutcome by adding the ZIDPOST /api/zsc/revoke/:name— confirm a revoke landed by probing- Rate limiter reference — the 5-in-60-Z window