---
title: "Replace the AI policy"
method: PUT
path: "/v1/ai/policy"
tags: ["AI Policy"]
---

# Replace the AI policy

`PUT /v1/ai/policy`

## Request

- Base URL: `https://api.talonic.com`
- URL: `https://api.talonic.com/v1/ai/policy`
- Auth: HTTP bearer

Replace the policy wholesale. Every field is optional in the body, but
an omitted field is CLEARED, which makes this the route to use when the
policy is generated from the customer's own source of truth. To change
one field while keeping the rest, use PATCH instead.

The write defaults to `status: active`, so the satisfiability gate
binds: a policy that would leave a registered operation with no
compliant route is refused with 400 `policy_unsatisfiable` and nothing
is stored. Only `active` policies are enforced at routing time;
`draft` and `shadow` versions are stored without taking effect.

Naming asymmetry, deliberate: top-level fields are snake_case, but
values INSIDE `model_classes` (`chain`, `requiredCapabilities`,
`fallback`) and the keys of `features` (`dataCapture`,
`markdownExtraction`, `assetVision`, `assetAnnotation`,
`classificationEscalation`, `richSummary`, `documentClassification`)
stay camelCase because they pass straight to the shared policy
validator.

## Request body

- object
  - `region_pin` 'us' | 'eu' | 'null', nullable: Hard residency constraint. A deployment in any other region is rejected, including globally-routed ones.
  - `allowed_providers` string[], nullable: Providers permitted to process this workspace's data. Null or omitted means every provider the platform permits.
  - `denied_models` string[], nullable: Models this workspace may never be routed to, whatever else permits them. Applies to explicit requests and every fallback chain step alike.
  - `model_substitutions` object: Remap one model onto another wherever the first would be chosen.
  - `default_models` object: Preferred model per speed tier where no class governs the call. Keys are fast, default, powerful.
  - `max_attempts` integer: Ceiling on provider attempts for one logical call.
  - `image_attachment_quality` 'low' | 'medium' | 'high' | 'null', nullable: How much the vision model spends rasterising an attached PDF page (Gemini media resolution; medium = 560 tokens per page, high = 1120). Image attachments are unaffected. Null = the deployment default. Omitting it on PUT clears it.
  - `model_classes` object: Named model lineage overrides. Values are camelCase: { description, chain: [{ model, deployments: [{ provider, region }] }], requiredCapabilities, fallback: chain | primary_only }.
  - `operation_classes` object: Per-operation class overrides, keyed by operation type.
  - `features` object: Feature toggles, camelCase keys. Absent toggles stay on.
  - `status` 'draft' | 'shadow' | 'active': Lifecycle state to save under. Only active is enforced at runtime.
  - `change_reason` string: Why this change is being made. Recorded on the stored version.

## Response `200`

The saved version plus the resulting effective policy view (the GET response body).

## Other responses

- `400`: The policy was refused and nothing was stored.
- `401`: Missing or invalid API key.
- `403`: The API key does not have the required scope.
- `429`: Daily rate limit exceeded.

---

[API](https://skmtc.dev/talonic/apis/talonic-api.md) · [All operations](https://skmtc.dev/talonic/apis/talonic-api/llms.txt) · [OpenAPI document](https://skmtc.dev/talonic/apis/talonic-api/revisions/678fe5f8c9c3?raw)
