Skip to main content
POST
/
v1
/
policies
Create a policy
curl --request POST \
  --url https://api-sandbox.featherhq.com/v1/policies \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '
{
  "name": "<string>",
  "description": "<string>",
  "enabled": true,
  "scope": "attachable",
  "metadata": {},
  "check_config": {},
  "action_config": {},
  "tool_target": "<string>",
  "mode": "monitor",
  "timeout_ms": 2,
  "strictness": "relaxed",
  "priority": 0
}
'
{
  "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "organization_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "name": "<string>",
  "enabled": true,
  "scope": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "updated_at": "2023-11-07T05:31:56Z",
  "description": "<string>",
  "active_revision_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "active_revision": {
    "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "policy_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
    "name": "<string>",
    "check_type": "<string>",
    "enforcement_point": "<string>",
    "action": "<string>",
    "mode": "<string>",
    "on_error": "<string>",
    "strictness": "<string>",
    "priority": 123,
    "created_at": "2023-11-07T05:31:56Z",
    "updated_at": "2023-11-07T05:31:56Z",
    "description": "<string>",
    "check_config": {},
    "action_config": {},
    "tool_target": "<string>",
    "timeout_ms": 123,
    "created_by": "<string>"
  },
  "metadata": {}
}

Authorizations

x-api-key
string
header
required

Body

application/json

Create a policy + its initial main revision in one call.

Identity fields (name/description/metadata) plus the full revision config. The initial revision is created and set active.

name
string
required
Required string length: 1 - 255
check_type
enum<string>
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.
Available options:
expression,
llm_judge
enforcement_point
enum<string>
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.

Available options:
input,
pre_tool,
post_tool,
agent_response
action
enum<string>
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.

Available options:
block,
redact,
append,
require_approval,
handoff
description
string | null
enabled
boolean
default:true
scope
enum<string>
default:attachable

Who the policy applies to.

organization policies auto-apply to every assistant in the org (NOT listed in an assistant's policy_refs). attachable policies apply only where an assistant revision opts in via policy_refs.

Available options:
organization,
attachable
metadata
Metadata · object
check_config
Check Config · object
action_config
Action Config · object
tool_target
string | null
mode
enum<string>
default: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).

Available options:
enforce,
monitor
on_error
enum<string> | null

What to do when a check errors/times out.

Action-derived default (v2): block action → fail_closed; else fail_open.

Available options:
fail_open,
fail_closed
timeout_ms
integer | null
Required range: x >= 1
strictness
enum<string>
default: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.

Available options:
strict,
relaxed
priority
integer
default:0

Response

Successful Response

id
string<uuid>
required
organization_id
string<uuid>
required
name
string
required
enabled
boolean
required
scope
string
required
created_at
string<date-time>
required
updated_at
string<date-time>
required
description
string | null
active_revision_id
string<uuid> | null
active_revision
PolicyRevisionResponse · object
metadata
Metadata · object