Targets
Each rule blocks or allows a single value of one of these target types:
Country rules are cache-only: PromptGuard does not call out to a GeoIP service on the hot path. If the inbound IP isn’t in the cache yet, country rules are skipped for that request and the cache is populated lazily by the dashboard’s geo distribution endpoint. You can pre-warm the cache by visiting the Overview page.
Semantics
The decision logic is intentionally boring and predictable:- Block always wins. If any active block rule matches the request, reject with
403 access_list_block. Done. - Non-empty allow list flips to default-deny. If the project (or user) has any active allow rule, the request must match at least one allow rule to proceed. Otherwise reject.
- Otherwise, allow. No rules and no allow list = no opinion = let the policy engine decide.
Scope: project vs. user
Each rule lives at one of two scopes:- Project-scoped (
project_idset) — the tightest scope. Use when one project needs different access rules from the rest of your account. - User-scoped (
project_idisNULL) — applies to every project you own. Convenient default for “block this abusive user across all my apps”.
check_access evaluates both scopes in the same query, so a user-wide block plus a project-scoped allow behave exactly the way you’d expect: the block fires.
Recipes
Block a specific abusive end-user across all projects
Block a specific abusive end-user across all projects
project_id → user-wide. The next call from this user, on any project, returns 403.Lock one project to a single allowed CIDR
Lock one project to a single allowed CIDR
10.0.0.0/8 is rejected.Country-block with an expiry
Country-block with an expiry
expires_at lets the rule auto-deactivate without a follow-up DELETE.What gets denied
A blocked request returns403 with this body:
rule_id is the access-list rule that fired, so your client (or your support team) can immediately point at the row in the dashboard.