---
title: "Create a policy revision"
method: POST
path: "/v1/policies/{policy_id}/revisions"
tags: ["policies"]
---

# Create a policy revision

`POST /v1/policies/{policy_id}/revisions`

## Path parameters

- `policy_id` string, uuid, required

## Request body

- PolicyRevisionCreate — Author a new named revision of a policy (optionally cloned from another).
  - `name` string, required
  - `description` string, nullable
  - `based_on_revision_id` string, uuid, nullable
  - `check_type` 'expression' | 'llm_judge', required — How a policy decides whether content/state violates it. - ``expression``: a ``PolicyExprEvaluator`` boolean over turn state. - ``llm_judge``: a secondary LLM (via model_router) judges against ``guardrail_text``.
  - `check_config` object
  - `enforcement_point` 'input' | 'pre_tool' | 'post_tool' | 'agent_response', required — Where in a turn a policy's check fires (v2: one point per policy). ``agent_response`` is the single author-facing reply point — the v1 ``response`` (per-streamed-unit) + ``post_response`` (complete reply) split is an internal runtime detail now, selected by the platform-derived enforcement strategy (buffer-and-gate vs per-unit), not an authored distinction.
  - `action` 'block' | 'redact' | 'append' | 'require_approval' | 'handoff', required — What happens when a check fails. - ``block``: emit a canned safe message, raise ``PolicyViolationError``, short-circuit. - ``redact``: deterministic regex/truncate (NO LLM rewrite). - ``append``: append a disclaimer. - ``require_approval``: route through the HITL approval seam (``pre_tool`` only). - ``handoff``: hand off via ``HandoffService`` (source="policy"). The v1 ``monitor`` action is gone — observe-only is the ``monitor`` *mode* now.
  - `action_config` object, nullable
  - `tool_target` string, nullable
  - `mode` 'enforce' | 'monitor' — The author's INTENT dial — act vs observe. Channel-independent. - ``enforce``: the policy acts on a violation (block / redact / append / require_approval / handoff) per the platform-derived strategy. - ``monitor``: shadow/canary — the check runs and records ``would_be_action`` but never affects the turn. The safe-rollout default. The TRANSPORT property v2 conflated into ``enforcement_mode`` (buffer-and-gate vs best-effort) is now platform-derived from ``transport_class`` at runtime (:func:`src.policy.resolution.resolve_strategy`), never authored. New-policy default *selection* is ``monitor`` (shadow-first; set at the schema layer).
  - `on_error` 'fail_open' | 'fail_closed' — What to do when a check errors/times out. Action-derived default (v2): ``block`` action → fail_closed; else fail_open.
  - `timeout_ms` integer, nullable
  - `strictness` 'strict' | 'relaxed' — The streaming latency/guarantee dial (renamed from the v2 ``severity``). - ``strict``: always enforce before the user sees anything. On a STREAMING transport this holds/buffers (or incrementally gates), accepting brief added latency; on a BLOCKING transport gating is free. - ``relaxed``: enforce without slowing the conversation — best-effort on streaming transports (content may stream while the check runs), but still a FULL gate on blocking transports (gating is free there). ``relaxed`` never means "off". Configurable only at ``input``·llm_judge and ``agent_response``·expression; forced (and hidden in the UI) elsewhere. New-policy default is ``relaxed``.
  - `priority` integer

## Response `201`

Successful Response

- PolicyRevisionResponse
  - `id` string, uuid, required
  - `policy_id` string, uuid, required
  - `name` string, required
  - `description` string, nullable
  - `check_type` string, required
  - `check_config` object
  - `enforcement_point` string, required
  - `action` string, required
  - `action_config` object, nullable
  - `tool_target` string, nullable
  - `mode` string, required
  - `on_error` string, required
  - `timeout_ms` integer, nullable
  - `strictness` string, required
  - `priority` integer, required
  - `created_by` string, nullable
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required

## Other responses

- `400` — Bad request
- `401` — Authentication required
- `422` — Validation Error

---

[API](https://skmtc.net/oneloop-hq/apis/feather-api.md) · [All operations](https://skmtc.net/oneloop-hq/apis/feather-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/oneloop-hq/feather-api/versions/888bdd5c076e/schema)
