> ## Documentation Index
> Fetch the complete documentation index at: https://spillway.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Guardrails

> Match-and-effect policies evaluated on every request — deny or flag.

A guardrail policy (`/api/policies`) matches requests on criteria you define and applies an
effect. Unlike budgets, guardrails aren't about spend — they're about *which* requests are
allowed to happen at all.

> [!WARNING]
>
> **`require_approval` is not available yet.** Creating a policy with that effect returns
> `422`. The effect is defined in the schema, but the mechanism that lets an *approved*
> request through on retry is still pending an ADR — shipping it without that would make
> `require_approval` a permanent deny wearing the wrong name. Use `deny` or `flag` today.

```jsonc theme={null}
// POST /api/policies   (session auth)
{
  "name": "block-gpt-4-for-interns",
  "description": "Interns can't use the expensive tier",
  "effect": "deny",
  "reason": "gpt-4.1 is not available to the intern team",
  "match": {
    "team_ids": ["<intern-team-uuid>"],
    "models": ["gpt-4.1"]
  },
  "enforcement": "enforce",
  "enabled": true
}
```

## Fields

| Field | Type | Notes |
| - | - | - |
| `name` | string, required | |
| `description` | string | |
| `effect` | `deny` \| `flag`, required | What happens when the policy matches. `require_approval` is a valid schema value but is rejected with `422` — see the warning above. |
| `reason` | string, required | Shown to the caller (deny/approval) and logged in the decision log. |
| `match` | object | `virtual_key_ids`, `team_ids`, `models`, `metadata`, `providers`, `endpoints` — any combination; a request matches if it satisfies the criteria you set. |
| `conditionCel` | string \| null | An additional [CEL](https://github.com/google/cel-spec) expression for conditions `match` can't express. Authoring-time errors (`cel_parse_error`, `cel_type_error`, and related codes) are returned on create/update, not discovered at request time. |
| `enforcement` | `shadow` \| `enforce`, default `enforce` | `shadow` evaluates and logs the decision without actually applying the effect — the way to test a new policy against live traffic before it can block anything. |
| `enabled` | boolean, default `true` | |
| `effectConfig` | object | Effect-specific configuration (for example, which approval policy a `require_approval` effect opens against). |

## The effects

* **`deny`** — the request is blocked with `403` before dispatch. No provider call, no
  charge.
* **`flag`** — the request proceeds normally. The match is recorded in the decision log for
  visibility, with no effect on the response.
* **`require_approval`** — *not available yet.* The intent is that the request is blocked
  with `403`, an approval request opens against the effect's approval policy, and the caller
  retries once it's granted. What isn't settled is the grant itself: what an approval records
  so the retry passes. Until an ADR specifies that, authoring the policy returns `422` rather
  than leaving you with a rule that denies forever and reports "approval required".

## Testing before you enforce

Two ways to see what a policy *would* do before it can block real traffic:

* Set `enforcement: "shadow"` on the policy itself — it evaluates on every real request and
  logs the decision, but never denies or gates one.
* `POST /api/policies/{id}/shadow-impact` — run a policy against recent traffic on demand to
  see its hit rate before flipping it to `enforce`.

`POST /api/policies/lint` validates a policy's `match`/`conditionCel` without creating it —
useful for catching a malformed CEL expression before it ever reaches the database.

## Where next

> **[Approvals & automation](https://spillway.mintlify.site/configuration/approvals-and-automation.md)**
>
> Approval chains for budget increases and key unpauses, and how to build one.

> **[Routing](https://spillway.mintlify.site/configuration/routing.md)**
>
> Reroute a model instead of denying the request outright.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.