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

# FastAPI Write Guard

> Synchronous mutation guard for FastAPI endpoints using Kernite execute decisions.

Use Kernite as a synchronous guard before every write endpoint.

## Route Pattern

```python theme={null}
from __future__ import annotations

from fastapi import FastAPI, HTTPException, Request

from kernite import evaluate_execute

app = FastAPI()


def build_execute_request(req: Request, payload: dict) -> dict:
    principal_id = req.headers.get("x-principal-id", "api:unknown")
    return {
        "workspace_id": payload["workspace_id"],
        "principal": {
            "type": "token",
            "id": principal_id,
            "attributes": {"role": payload.get("role", "member")},
        },
        "object_type": "invoice",
        "operation": "create",
        "payload": payload,
        "policy_context": {
            "governed": True,
            "selected_policies": [
                {
                    "policy_key": "invoice_create_guard",
                    "policy_version": 1,
                    "effect": "allow",
                    "rules": [
                        {
                            "rule_key": "require_currency",
                            "rule_definition": {
                                "type": "required_fields",
                                "fields": ["currency"],
                            },
                            "reason_code": "required_currency",
                            "reason_message": "currency is required.",
                        }
                    ],
                }
            ],
        },
    }


@app.post("/invoices")
async def create_invoice(req: Request, payload: dict):
    execute_request = build_execute_request(req, payload)
    governance = evaluate_execute(
        execute_request,
        idempotency_key=req.headers.get("idempotency-key"),
    )

    if governance["data"]["decision"] != "approved":
        raise HTTPException(
            status_code=403,
            detail={
                "reason_codes": governance["data"]["reason_codes"],
                "governance": governance,
            },
        )

    created_invoice = {"id": "inv-001", **payload}
    return {"ok": True, "data": created_invoice, "governance": governance}
```

## Integration Rules

* Evaluate in the same request path right before mutation.
* Branch on `data.decision`, not `message`.
* Persist `ctx_id`, `data.trace_hash`, and `data.idempotency_key` with the write.
* Do not trust a cached allow flag from previous requests.
