Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.promptguard.co/llms.txt

Use this file to discover all available pages before exploring further.

Access lists are a per-project (or per-user) firewall that runs before the policy engine. They’re the right tool for “I know I never want to hear from this source again” — block in O(1), no ML inference, no upstream cost.

Targets

Each rule blocks or allows a single value of one of these target types:
Target typeMatches againstExample value
ipExact source IP of the inbound request203.0.113.10
ip_cidrSource IP inside a CIDR block203.0.113.0/24
end_userThe X-End-User header on the inbound requestcustomer-42
countryISO-3166 alpha-2 code, looked up via the cached GeoIP tableRU
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:
  1. Block always wins. If any active block rule matches the request, reject with 403 access_list_block. Done.
  2. 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.
  3. 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_id set) — the tightest scope. Use when one project needs different access rules from the rest of your account.
  • User-scoped (project_id is NULL) — 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

curl -X POST https://api.promptguard.co/dashboard/access-lists \
  -H "Authorization: Bearer $TOKEN" -H "X-CSRF-Token: $CSRF" \
  -H "Content-Type: application/json" \
  -d '{
    "list_type": "block",
    "target_type": "end_user",
    "value": "customer-42",
    "reason": "Repeatedly attempted PII extraction"
  }'
No project_id → user-wide. The next call from this user, on any project, returns 403.
curl -X POST https://api.promptguard.co/dashboard/access-lists \
  -H "Authorization: Bearer $TOKEN" -H "X-CSRF-Token: $CSRF" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": "...",
    "list_type": "allow",
    "target_type": "ip_cidr",
    "value": "10.0.0.0/8"
  }'
The first allow rule on the project flips it to default-deny. Anything outside 10.0.0.0/8 is rejected.
curl -X POST https://api.promptguard.co/dashboard/access-lists \
  -H "Authorization: Bearer $TOKEN" -H "X-CSRF-Token: $CSRF" \
  -H "Content-Type: application/json" \
  -d '{
    "list_type": "block",
    "target_type": "country",
    "value": "KP",
    "expires_at": "2026-12-31T00:00:00Z",
    "reason": "Sanctions"
  }'
expires_at lets the rule auto-deactivate without a follow-up DELETE.

What gets denied

A blocked request returns 403 with this body:
{
  "error": {
    "message": "Repeatedly attempted PII extraction",
    "type": "access_denied",
    "code": "access_list_block",
    "rule_id": "dd04502f-...",
    "target_type": "end_user"
  }
}
The 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.