---
title: "Validate Cedar policy content against a schema"
method: POST
path: "/zones/{zone_id}/policy-validations"
tags: ["PolicyValidations"]
---

# Validate Cedar policy content against a schema

`POST /zones/{zone_id}/policy-validations`

## Request

- Base URL: `https://docs.keycard.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://docs.keycard.ai/zones/{zone_id}/policy-validations`
- Auth: one of:
  - HTTP bearer
  - OAuth 2
    - Client credentials
    - Token URL: `/service-account-token`

## Path parameters

- `zone_id` string, required

## Headers

- `X-API-Version` string
- `X-Client-Request-ID` string, uuid

## Request body

- PdpValidatePolicyContentRequest
  - `cedar_json` object, nullable: Cedar policy in JSON representation. Mutually exclusive with cedar_raw.
  - `cedar_raw` string, nullable: Cedar policy in human-readable Cedar syntax. Mutually exclusive with cedar_json.
  - `schema_version` string, required: Schema version to validate against. Must not be archived.

## Response `200`

Validation result

- PdpPolicyValidationResult
  - `valid` boolean, required: True if the policy passes schema validation with no errors.
  - `schema_version` string, required: Schema version validated against (echo back).
  - `errors` PdpPolicyValidationDiagnostic[], required: Validation errors. Empty array when valid.
    - `message` string, required: Human-readable description of the validation issue.
    - `severity` 'error' | 'warning': Severity of the diagnostic. Optional and additive; older clients that only read `message` can ignore it. Diagnostics under `errors` are `error`; those under `warnings` are `warning`.
    - `range` PdpSourceRange: Half-open source range [start, end) locating a diagnostic in the submitted policy text. Optional: present only when the engine can map the finding to a span. Populated for parse/syntax errors and for semantic findings when the policy was submitted as `cedar_raw`; absent for whole-policy semantic findings (no single span) and for policies submitted as `cedar_json` (the JSON AST carries no source locations).
      - `start` PdpSourcePosition, required: A position in the submitted policy text.
        - `line` integer, required: 1-based line number.
        - `column` integer, required: 1-based column number (counts Unicode scalar values).
        - `offset` integer, required: 0-based byte offset into the UTF-8 policy text.
      - `end` PdpSourcePosition, required: A position in the submitted policy text.
        - `line` integer, required: 1-based line number.
        - `column` integer, required: 1-based column number (counts Unicode scalar values).
        - `offset` integer, required: 0-based byte offset into the UTF-8 policy text.
    - `code` string: Machine-readable kind of the diagnostic (e.g. `unknown_action`, `parse_error`). Optional and additive; absent when the finding has no specific code.
    - `help` string: Optional advisory text, rendered by clients as secondary text below the primary message.
    - `data` object: Optional structured details keyed by the diagnostic `code`, so consumers need not parse `message`. For `unknown_action`: `{"action_uid": "..."}`.
  - `warnings` PdpPolicyValidationDiagnostic[], required: Validation warnings. May be non-empty even when valid is true. References to actions absent from the schema are reported here as per-occurrence warnings with code `unknown_action` (partitioned out of errors: they do not make valid false).
    - `message` string, required: Human-readable description of the validation issue.
    - `severity` 'error' | 'warning': Severity of the diagnostic. Optional and additive; older clients that only read `message` can ignore it. Diagnostics under `errors` are `error`; those under `warnings` are `warning`.
    - `range` PdpSourceRange: Half-open source range [start, end) locating a diagnostic in the submitted policy text. Optional: present only when the engine can map the finding to a span. Populated for parse/syntax errors and for semantic findings when the policy was submitted as `cedar_raw`; absent for whole-policy semantic findings (no single span) and for policies submitted as `cedar_json` (the JSON AST carries no source locations).
      - `start` PdpSourcePosition, required: A position in the submitted policy text.
        - `line` integer, required: 1-based line number.
        - `column` integer, required: 1-based column number (counts Unicode scalar values).
        - `offset` integer, required: 0-based byte offset into the UTF-8 policy text.
      - `end` PdpSourcePosition, required: A position in the submitted policy text.
        - `line` integer, required: 1-based line number.
        - `column` integer, required: 1-based column number (counts Unicode scalar values).
        - `offset` integer, required: 0-based byte offset into the UTF-8 policy text.
    - `code` string: Machine-readable kind of the diagnostic (e.g. `unknown_action`, `parse_error`). Optional and additive; absent when the finding has no specific code.
    - `help` string: Optional advisory text, rendered by clients as secondary text below the primary message.
    - `data` object: Optional structured details keyed by the diagnostic `code`, so consumers need not parse `message`. For `unknown_action`: `{"action_uid": "..."}`.

## Other responses

- `400`: bad request error response when caller supplied invalid input data
- `401`: unauthorized error response when caller session is not authenticated
- `403`: forbidden error response when caller does not have permissions to a resource
- `404`: not found error response when caller does not have permission to see a resource or the resource does not exist
- `429`: rate limit exceeded error response when caller has exhausted api limits for the given time period
- `500`: internal server error response when server encountered error of its own creation
- `503`: service unavailable error when server you're attempting to reach is not available
- `default`: internal server error response when server encountered error of its own creation

## Changes

- **2026-10-16** `0cfaff865771`: 16 breaking, 8 warning, 80 info
  - the response property `details/items/field` became optional for the status `400`
  - the response property `details/items/field` became optional for the status `401`
  - the response property `details/items/field` became optional for the status `403`
  - the response property `details/items/field` became optional for the status `404`
  - …100 more
- **2026-08-26** `d65d51379d93`: 10 info
  - added the optional property `errors/items/code` to the response with the `200` status
  - added the optional property `errors/items/data` to the response with the `200` status
  - added the optional property `errors/items/help` to the response with the `200` status
  - added the optional property `errors/items/range` to the response with the `200` status
  - …6 more
- **2026-04-02** `a52e80c8dfdc`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/keycardai/apis/keycard-ai-keycard-api/changes/zones/:zone_id/policy-validations/post.md)

---

[API](https://skmtc.dev/keycardai/apis/keycard-ai-keycard-api.md) - [All operations](https://skmtc.dev/keycardai/apis/keycard-ai-keycard-api/llms.txt) - [OpenAPI document](https://skmtc.dev/keycardai/apis/keycard-ai-keycard-api/revisions/0dee67e0a73a?raw)
