---
title: "Apply a template"
method: POST
path: "/api/v1/templates/{id}/apply"
tags: ["Templates"]
deprecated: true
---

# Apply a template

`POST /api/v1/templates/{id}/apply`

## Request

- Base URL: `https://agent.getaxonflow.com`
- URL: `https://agent.getaxonflow.com/api/v1/templates/{id}/apply`
- Auth: none declared. Required headers: `X-Tenant-ID`
- TypeScript: <https://skmtc.dev/getaxonflow/apis/axonflow-policy-management-api/docs/api/v1/templates/:id/apply/post.ts> (a function with typed inputs; its response is checked against the schema)

> **Deprecated.**

Create a new policy from a template by providing variable values.
Templates may have required and optional variables that customize
the generated policy.

**v11:** the generated policy is written to `dynamic_policies`, which
`migrations/core/172` makes read-only to the application roles, so on a
deployment whose database connection cannot write it this route answers
`409 LEGACY_POLICY_WRITE_FROZEN` before the request body is read,
whatever it contains, as the policy write routes do. An owner-role
deployment still applies.

## Headers

- `X-User-ID` string

## Request body

- ApplyTemplateRequest
  - `policy_name` string, required: Name for the new policy
  - `description` string: Optional policy description
  - `variables` object, required: Variable values for the template
  - `enabled` boolean: Whether to enable the policy immediately
  - `priority` integer: Policy priority (overrides template default)

## Response `201`

Policy created from template

- ApplyTemplateResponse
  - `success` boolean
  - `policy` PolicyResource
    - `id` string: Unique policy identifier
    - `name` string: Human-readable policy name
    - `description` string: Detailed policy description
    - `type` 'content' | 'user' | 'risk' | 'cost' | 'context_aware' | 'media' | 'rate-limit' | 'budget' | 'time-access' | 'role-access' | 'mcp' | 'connector': Policy type determines evaluation context: - `content`: Evaluates request/response content - `user`: Evaluates user attributes - `risk`: Evaluates risk scores - `cost`: Evaluates cost estimates - `context_aware`: Context-aware controls (tenant isolation, debug restriction, sensitive-data control) - `media`: Media governance policies (multimodal image governance) - `rate-limit`, `budget`, `time-access`: MCP rate/budget controls - `role-access`, `mcp`, `connector`: MCP access controls
    - `category` string: Policy category (dynamic-risk, dynamic-compliance, media-safety, etc.)
    - `tier` 'system' | 'organization' | 'tenant': Policy tier in the hierarchy (system policies are immutable)
    - `conditions` PolicyCondition[]: Conditions that must all match (AND logic)
      - `field` 'query' | 'response' | 'user.email' | 'user.role' | 'user.department' | 'user.tenant_id' | 'risk_score' | 'request_type' | 'connector' | 'cost_estimate' | 'media.has_faces' | 'media.face_count' | 'media.has_biometric_data' | 'media.nsfw_score' | 'media.violence_score' | 'media.content_safe' | 'media.document_type' | 'media.is_sensitive_document' | 'media.has_pii' | 'media.pii_types' | 'media.has_extracted_text' | 'media.extracted_text_length' | 'step.gate_count' | 'step.completion_count' | 'step.prior_completion_status' | 'step.prior_output_available' | 'step.last_decision' | 'step.first_attempt_age_seconds' | 'step.idempotency_key', required: Field to evaluate. `media.*` fields apply to media governance policies (multimodal image governance); `step.*` fields are retry-aware workflow step fields for WCP policies.
      - `operator` 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'contains_any' | 'regex' | 'greater_than' | 'less_than' | 'in' | 'not_in', required: Comparison operator for conditions
      - `value` union, required: Value to compare against
        - string
        - number
        - boolean
        - string[]
    - `actions` PolicyAction[]: Actions to execute when policy matches
      - `type` 'block' | 'require_approval' | 'redact' | 'warn' | 'alert' | 'log' | 'route' | 'modify_risk', required: Action to take when policy matches: - `block`: Block the request with message - `require_approval`: Hold the request for human approval (HITL) - `redact`: Redact sensitive content from response - `warn`: Allow the request but attach a warning - `alert`: Send alert to configured channel - `log`: Log to audit trail - `route`: Route to specific provider - `modify_risk`: Adjust risk score
      - `config` object: Action-specific configuration
    - `priority` integer: Higher priority policies are evaluated first
    - `enabled` boolean: Whether the policy is active
    - `version` integer: Policy version number, incremented on each update
    - `tenant_id` string: Owning tenant ID
    - `organization_id` string: The organisation that owns this policy. Since #3490 the organisation is what SELECTS a policy row, at every tier -- this is not an organization-tier-only field, and the previous wording described the retired organization_id COLUMN rather than this resource field.
    - `tags` string[]: Tags for categorization
    - `created_at` string, date-time: Creation timestamp
    - `updated_at` string, date-time: Last update timestamp
    - `created_by` string: User who created the policy
    - `updated_by` string: User who last updated the policy
    - `deleted_at` string, date-time: Soft-delete timestamp (present only on deleted policies)
  - `usage_id` string: Unique ID for this template usage (for analytics)
  - `message` string: Success message

## Other responses

- `400`: Request validation failed
- `401`: Missing or invalid tenant ID
- `404`: Policy not found
- `409`: The legacy policy tables are read-only. `migrations/core/172` revoked INSERT, UPDATE, DELETE and TRUNCATE on `static_policies` and `dynamic_policies` from the application roles, and this endpoint writes them, so the write is refused permanently rather than transiently. It is not an entitlement fact: no licence, edition or upgrade changes it. Author policies through the typed authoring route (`/api/v1/typed-policies`, in `orchestrator-api.yaml`) instead. Reads on this endpoint are unaffected. A deployment whose connection may still write the tables (the database owner; a property of the connection, not of `AXONFLOW_DB_USE_APP_ROLE` alone) is not bound by the revoke and does not receive this response. Where the connection cannot write them, the create, update and bulk-import routes answer this before reading the request body, whatever it contains.
- `500`: Internal server error

---

[API](https://skmtc.dev/getaxonflow/apis/axonflow-policy-management-api.md) - [All operations](https://skmtc.dev/getaxonflow/apis/axonflow-policy-management-api/llms.txt) - [OpenAPI document](https://skmtc.dev/getaxonflow/apis/axonflow-policy-management-api/revisions/302fbde24320?raw)
