Skip to main content

AI Policy Overview

Control which AI providers, regions, and models may process your documents. Read, write, and verify the tenant AI policy through the /v1/ai API surface.

The AI Policy API puts the answer to "which models may touch our data" under the customer's own control. Every AI call the platform makes on a workspace's behalf passes through a routing resolver, and the resolver is governed by the workspace's AI policy: which providers are permitted, which region deployments must live in, and which individual models are denied outright. The /v1/ai surface reads that policy, writes it, and proves what it does, all against the live resolver rather than against documentation that can drift.

The policy separates mandatory constraints from preferences. region_pin, allowed_providers, and denied_models are hard constraints, enforced at routing time for every call: a deployment outside the pinned region or on a disallowed provider is never a candidate, whatever else the request asks for. Everything else in the policy (default models, substitutions, class overrides, attempt ceilings) is preference: it steers which compliant candidate is chosen but never overrides a mandatory constraint.

denied_models exists because a provider allowlist cannot express "this vendor, but not that one model". A regulated customer often needs exactly that: the provider relationship is approved, one specific model is not. Denial is narrowing only. It removes candidates and never adds one, and it applies to explicitly requested models and to every step of every fallback chain alike, so a denied model cannot re-enter through a substitution or a chain walk.

The guarantee the whole feature rests on is that routing fails closed. If the policy leaves an operation with no compliant route, the call for that operation fails; it does not silently reach a provider the policy forbids. The satisfiability gate makes this safe to rely on: activating a policy that would strand a registered operation is refused with a 400 that names the stranded operations, so a workspace cannot accidentally activate its way into a broken state. Operations listed in advisory_warnings warn but do not block activation.

Model Classes and Operations

Routing is organized in two layers. An operation (for example extraction or classification) maps to a model class, and a class is an ordered chain of models with declared fallback behaviour: chain walks the chain until a compliant candidate answers, primary_only refuses to substitute. Overriding a class or remapping an operation onto a different class is how a customer says "use this model for this task". The mandatory constraints still apply on top: an override can never route to a model the policy denies or a provider it disallows.

Beneath the tenant policy sits the platform provider floor, a deployment-level constraint that intersects with the policy and can only narrow it. A workspace cannot widen past the floor, whatever it submits; constraints.platform_provider_floor in the policy read shows exactly what the floor is. Self-hosted or customer-operated inference endpoints appear in the catalog as deployments with custom_endpoint: true. Deliberately, no endpoint host and no credential detail is ever returned by any route on this surface, and per-tenant endpoint credentials are out of scope by design: endpoints are declared at deployment level.

All /v1/ai routes require a workspace-scoped API key. The workspace is taken from the authenticated key and from nowhere else; no route accepts a customer identifier, so there is no request shape that reads or writes another workspace's policy. A master-view key is rejected with 400 workspace_scope_required.

Worked Example: Pinning EU Residency and Denying One Model

A customer wants a contractual guarantee: EU region only, one provider, and one specific model excluded even though its provider is allowed. First, dry-run the current state to see what extraction would route to today, pinning the model that is about to be denied.

cURL: 1. Dry-run the model you intend to deny

curl -X POST "https://api.talonic.com/v1/ai/routes:explain" \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation_type": "extraction", "model": "claude-opus"}'

Then write the policy. PUT replaces it wholesale and defaults to activating, so the satisfiability gate binds at this moment: if the combination of region pin, provider allowlist, and denial would strand a registered operation, the write is refused with policy_unsatisfiable and nothing is stored. The refusal is the verification; a policy that activates is a policy every gating operation can still route under.

cURL: 2. Activate the residency policy

curl -X PUT "https://api.talonic.com/v1/ai/policy" \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "region_pin": "eu",
    "allowed_providers": ["bedrock"],
    "denied_models": ["claude-opus"],
    "change_reason": "Contractual EU residency"
  }'

Finally, prove the result. Re-run the same dry-run: the denied model now appears under rejected with reason model_denied, and the candidate chain contains only EU deployments of the allowed provider. Then read GET /v1/ai/models for the full picture: every model in the catalog annotated as reachable or not, with the constraint that stopped it. That response, not a policy document, is the evidence of which models can touch the workspace's data.

cURL: 3. Verify the route, then read the catalog

curl -X POST "https://api.talonic.com/v1/ai/routes:explain" \
  -H "Authorization: Bearer $TALONIC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation_type": "extraction"}'

curl "https://api.talonic.com/v1/ai/models" \
  -H "Authorization: Bearer $TALONIC_API_KEY"
Only active policies are enforced at runtime. A policy saved with status: "draft" or "shadow" is stored and versioned but does not affect routing, and the resolver keeps answering from the currently active policy (or the platform default when none is active). Submitting a residency constraint and forgetting to activate it means it does not bind.