---
title: "Create or replace a policy set draft"
method: PUT
path: "/zones/{zone_id}/policy-sets/{policy_set_id}/draft"
tags: ["PolicySetDrafts"]
---

# Create or replace a policy set draft

`PUT /zones/{zone_id}/policy-sets/{policy_set_id}/draft`

Full replacement of the draft state. Creates the draft if it does not exist, replaces it if it does. Standard REST PUT idempotency — the caller provides the complete desired state.

## Path parameters

- `zone_id` string, required
- `policy_set_id` string, required

## Headers

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

## Request body

- PdpUpsertPolicySetDraftRequest
  - `manifest` PdpPolicySetManifest, required
    - `entries` PdpPolicySetManifestEntry[], required
      - `policy_id` string, required
      - `policy_version_id` string, required
      - `sha` string — SHA-256 of the policy version content, populated by the server
  - `schema_version` string, required
  - `name` string
  - `description` string

## Response `200`

The upserted policy set draft

- PdpPolicySetDraft
  - `policy_set_id` string, required
  - `manifest` PdpPolicySetManifest, required
    - `entries` PdpPolicySetManifestEntry[], required
      - `policy_id` string, required
      - `policy_version_id` string, required
      - `sha` string — SHA-256 of the policy version content, populated by the server
  - `schema_version` string, required
  - `name` string, nullable
  - `description` string, nullable
  - `base_version_id` string, nullable — ID of the policy set version this draft was hydrated from. Null when the draft was created without an existing version.
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `updated_by` string, required
  - `warnings` PdpPolicySetDraftManifestWarning[] — Warnings about manifest entries that would prevent creating a version from this draft. Present only when there are warnings; omitted when empty.
    - `policy_id` string, required
    - `policy_version_id` string, required
    - `type` 'policy_version_archived' | 'schema_version_mismatch', required
    - `message` string, required — Human-readable description of the warning, e.g. 'validated against schema "2026-02-24", draft targets "2026-03-16"' or 'policy version is archived'.
    - `detail` PdpManifestWarningDetail — Additional structured context for a manifest warning. The shape depends on the warning type.
      - `policy_schema_version` string — Schema version the policy version was validated against. Present only for schema_version_mismatch warnings.
      - `draft_schema_version` string — Schema version the draft targets. Present only for schema_version_mismatch warnings.

## 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
- `409` — Conflict - concurrency conflict
- `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

---

[API](https://skmtc.net/keycardai/apis/untitled-api.md) · [All operations](https://skmtc.net/keycardai/apis/untitled-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/keycardai/untitled-api/versions/2f5033ed4491/schema)
