POST /api/zsc/revoke/:name
Remove a ZID from the secret's permissions[] array. Subsequent
ZeqContext.read() calls from that ZID will be rejected by the
permission gate and write a secret_denied audit row.
Idempotent — revoking a ZID that isn't in permissions[] is a no-op.
You cannot revoke the owner (bound_zid) via this endpoint; for that,
update the entire row via /set with a new boundZid.
Auth
Admin cookie (zeq_admin) required.
Path parameters
| Param | Type | Notes |
|---|---|---|
name | string | The vault key. |
Request
curl -H "Cookie: zeq_admin=$ADMIN_JWT" \
-H "Content-Type: application/json" \
-X POST https://YOUR-FRAMEWORK/api/zsc/revoke/STRIPE_SECRET_KEY \
-d '{ "zid": "ZEQ07111111111" }'
Body fields
| Field | Required | Type | Notes |
|---|---|---|---|
zid | yes | string | The ZID to remove from permissions[]. |
Response · 200 OK
{
"ok": true,
"name": "STRIPE_SECRET_KEY",
"zid": "ZEQ07111111111",
"permissions": ["ZEQ07222222222"]
}
permissions is the complete updated list after the revoke.
Errors
| Status | error | Cause |
|---|---|---|
400 | name + zid required | Missing path segment or body field. |
401 | unauthorized | Admin cookie missing/invalid. |
404 | NOT_FOUND | No row with this name. |
500 | INTERNAL_ERROR | DB error. |
Audit row
transition_type = "secret_set"
actor_zid = <the admin's ZID>
payload_json = { name, purpose: "revoked", revoked_zid: <zid>, permissions: [...] }
proof_digest = SHA-256(name | actor_zid | transition_id | "revoked")
Active rate-limit window survives revoke
If the target ZID has an active denial window (5+ denied attempts in the last 60 Zeqonds, see Rate limiter), revoking does not reset the limit. The ZID stays rate-limited until the window expires. This is by design — a grant + revoke loop shouldn't be a way to clear an attacker's denial state.
Related
POST /api/zsc/grant/:name— add a ZIDPOST /api/zsc/probe-permission— confirm the revoke took effect