Docs

Publish a policy

POST
/policies

Publishes the project's policy for an operation as a new immutable revision, creating the policy on its first publish. The newest revision applies to the next time the operation runs; nothing already stored is re-evaluated, so a stricter password policy applies the next time a password is set.

The request is typed by operation: an unknown operation or setting, or a value of the wrong type or outside its bounds, answers req.invalid like any malformed request. The operation's template then checks the config again, together with the rules that relate settings to each other (a min_length above max_length), and answers pol.invalid. Its details.details.violations lists everything that failed, settings first, then rules: {"setting": "min_length"} for one setting, or {"config_rule": "min_length_not_above_max_length", "settings": ["min_length", "max_length"]} for a rule across settings, with the settings it reads. A setting left out is off, and {} switches every rule off; there are no defaults.

Authorization

oauth2 policy.write
headerAuthorizationBearer <token>

Scope: policy.write

Query Parameters

project_id*string

The unique identifier of the project

Match^[a-zA-Z0-9_-]+$

Request Body

application/json
  1. body

A publish of the password policy, checked before a password is set.

operation*"auth.factor.password.set"

The operation the policy guards.

Value in"auth.factor.password.set"
config*

The settings of an auth.factor.password.set policy. Every setting is optional; a setting left out switches its rule off, and {} switches every rule off. There are no defaults. The bounds are technical limits, not recommendations; the server's template checks the same bounds.

Response Body

The revision was published.

application/json
  1. response

One revision of a project's auth.factor.password.set policy (ADR 066). id is shared by every revision of the operation's policy; revision_id names this revision.

id*policy-id

The identifier of a policy, shared by all of its revisions.

Match^pol_[a-zA-Z0-9_-]+$
revision_id*policy-revision-id

The identifier of one immutable revision of a policy.

Match^polrev_[a-zA-Z0-9_-]+$
project_id*project-id

The project the policy belongs to.

Match^[a-zA-Z0-9_-]+$
operation*"auth.factor.password.set"

The operation the policy guards.

Value in"auth.factor.password.set"
config*

The settings of an auth.factor.password.set policy. Every setting is optional; a setting left out switches its rule off, and {} switches every rule off. There are no defaults. The bounds are technical limits, not recommendations; the server's template checks the same bounds.

created_at*string

When the operation's policy was first published.

Formatdate-time
updated_at*string

When this revision was published.

Formatdate-time
Example Request
import { createZitadelClient } from "@zitadel/api/client";const client = createZitadelClient({  baseUrl: process.env.ZITADEL_URL ?? "http://localhost:8080",  token: process.env.ZITADEL_PROJECT_SECRET!, // server-side only});const result = await client.publishPolicy(  {    operation: "auth.factor.password.set",    config: { min_length: 12, history_depth: 4 },  },  { project_id: "proj_01KWH1P4MYS7F0N9WD3P2E4YM5" },);
Example Response
{  "id": "pol_01KXA4F3Q8R7F0N9WD3P2E4YM5",  "revision_id": "polrev_01KXB7C2M4N7F0N9WD3P2E4YM7",  "project_id": "proj_01KWH1P4MYS7F0N9WD3P2E4YM5",  "operation": "auth.factor.password.set",  "config": {    "min_length": 12,    "history_depth": 4  },  "created_at": "2026-10-20T09:00:00Z",  "updated_at": "2026-10-20T10:30:00Z"}

Was this helpful?