Key allow-list vs validation_scope
The API key’s Rulepacks setting is the outer boundary. Create keys in Command (Settings → API → Keys) and set Rulepacks on each key. That allow-list caps which managed packs the key may use.
validation_scope only narrows live enforcement to a subset of already-active rules, rule packs, and imports. It cannot broaden key permissions. If a request scopes to a pack the key does not allow, that pack is outside the key boundary.
Discover pack ids with Rule Packs (GET /api/rulepacks/). Do not hard-code pack ids you have not confirmed for your account.
Two patterns
Pattern A — one API key per tenant. Mint a key per tenant and set Rulepacks on the key. Every call with that key stays inside that allow-list. Simplest isolation when tenants are few and stable. Pattern B — one key, scope per request. Keep a tenant table and passvalidation_scope on every call. Best when tenants are many or change often. The shared key’s allow-list remains the outer boundary; per-request scope only narrows further.
Activated custom rules from Import a Policy run for the account by default. For Pattern B, always pass validation_scope so a tenant does not pick up another tenant’s active imports.
Pattern A
Use the tenant’s key. Always passvalidation_scope.imports on Pattern A too: the key Rulepacks allow-list does not isolate custom imports. Use that tenant’s import ids, or [] if the tenant has none.
Pattern B
One shared key. Look up the tenant’s activatedimport_id and pass validation_scope.imports on every call. Import ids come from Import a Policy, not invented fixtures. Set TENANT_IMPORT_ID.
Live validation_scope.rulepacks currently fails closed (fallback_reason: rulepack_scope_unsupported). Use Pattern A (per-tenant keys) to isolate managed packs; use Pattern B for tenant-specific imported policies.
Optional metadata is merged into the job (Enforce Content). Activity list filters are the documented query params on List Activity (from, to, status, agent_id, source, rule_id, search, cursor, limit) — do not assume arbitrary metadata keys are Activity filters.
Tenant-specific policies
A tenant’s own rulebook becomes animport_id through Import a Policy. Put that id in the tenant’s imports list. For either pattern, pass validation_scope.imports explicitly when multiple tenants share one ZeroDrift account. Calls then run the regulatory pack and tenant policy together when both are in scope.
Gotchas
- Missing
validation_scope.importsevaluates every active import on the account. Pass the tenant’s import ids (or[]) on Pattern A and Pattern B. validation_scopecannot widen the key. It only narrows within the key allow-list and already-active imports/rules.- Managed-pack request scope is not live.
validation_scope.rulepackscurrently returnsstatus: "failed"withfallback_reason: rulepack_scope_unsupported. Isolate managed packs with Pattern A until that path is supported. - Resolve ids. List packs with
GET /api/rulepacks/(for examplezd-us-securities). SetTENANT_IMPORT_IDfor Pattern B.
Next
Rule Packs
List managed and custom packs; use returned ids in
validation_scope.rulepacks.Export Activity
Pull the verdict log for reporting and threshold tuning.

