Submission, Review, Approval, and Archive Operations

Reference lifecycle decisions, exact draft preconditions, authenticated actors, and asynchronous delivery boundaries.

These application programming interface (API) commands govern saved policy work. Use the POLICY_API base and protected POLICY_AUTH_HEADER file from authentication. Every operation takes a required policy_id path string and no query parameters. Bodies use application/json and reject unknown fields.

Policy derives all actors from trusted identity. Do not send submittedBy, approvedBy, or an archiver identity in a body. Separate-user examples do not imply mandatory two-person enforcement.

A saved snapshot records proposal content at a particular draft head. Submission puts that head into review. It does not establish a governed revision. Approval creates the governed revision and queues separate publication work. Use the policy identifier in every {policy_id} path, not draftPolicyId or a snapshot identifier. Set POLICY_ID to that policy identifier. Before each draft command, read the current draft and retain its exact Draft-ETag as DRAFT_ETAG. For review decisions, use the submitted head you actually reviewed, not a pre-submission token. For archive, retain the current policy ETag as POLICY_ETAG instead.

POST /policies/{policy_id}/submit

Submit the exact saved draft for review. Require policy:edit and an active owner/editor policy grant. An audited recovery authority can override the grant requirement. Send the current Draft-ETag through If-Match.

The body is optional for clean work. When acknowledging permitted reviewable conflicts, supply:

FieldTypeRequirement
reviewNotesStringSupply 1–512 characters with nonblank trimmed text when sending a body.
acknowledgedConflictIdsArray of stringsInclude current reviewable blocking identifiers. Default to an empty array.
curl --fail-with-body -X POST \
  -H "@${POLICY_AUTH_HEADER:?Complete authentication setup}" \
  -H "If-Match: ${DRAFT_ETAG}" \
  "${POLICY_API}/policies/${POLICY_ID}/submit"

Optional acknowledgement body:

{
  "reviewNotes": "Reviewed the permitted findings and accepted their documented impact.",
  "acknowledgedConflictIds": ["current-reviewable-conflict-id"]
}

Return 200 with a policy summary and updated ETag and Draft-ETag headers. The compatibility status becomes submitted. draftState becomes in_review. Policy checks the saved validation binding and recompiles against current catalogs. Hard conflicts cannot receive acknowledgement. An eligible returned draft can enter review again without an intermediate save. Submission does not approve or publish. Reload the submitted draft and use its new Draft-ETag for the review decision. The token from before submission no longer identifies the current draft.

POST /policies/{policy_id}/request-changes

Return the current in-review draft to its author. Require policy:review, not an owner/editor grant. Send the reviewed current draft token through If-Match.

The request body contains this required reason field:

FieldTypeRequirement
reasonStringSupply 1–512 characters with nonblank trimmed text.

The current request schema enforces this reason length.

curl --fail-with-body -X POST \
  -H "@${POLICY_AUTH_HEADER:?Complete authentication setup}" \
  -H "Content-Type: application/json" \
  -H "If-Match: ${DRAFT_ETAG}" \
  --data '{"reason":"Narrow the resource scope before approval."}' \
  "${POLICY_API}/policies/${POLICY_ID}/request-changes"

Return 200 with the new draft summary:

{
  "draft": {
    "policyId": "policy-1",
    "draftPolicyId": "draft-1",
    "cycleNumber": 1,
    "proposedRevisionNumber": 1,
    "currentVersionId": 43,
    "draftStatus": "changes_requested",
    "etag": "W/\"draft-1.1.43\""
  }
}

Use the returned draft.etag for subsequent draft work. Policy preserves authored content and records the reviewer’s decision. An existing governed revision remains current.

POST /policies/{policy_id}/approve

Approve the exact reviewed in-review draft. Require policy:approve. Policy ownership alone does not grant approval. Send its current Draft-ETag through If-Match. Do not reuse the author’s token from before submission.

The required approval body accepts these review notes and conflict identifiers:

FieldTypeRequirement
reviewNotesStringSupply required review notes for every approval: 1–512 characters with nonblank trimmed text.
acknowledgedConflictIdsArray of stringsSupply permitted current conflict identifiers. Default to an empty array.
curl --fail-with-body -X POST \
  -H "@${POLICY_AUTH_HEADER:?Complete authentication setup}" \
  -H "Content-Type: application/json" \
  -H "If-Match: ${DRAFT_ETAG}" \
  --data '{"reviewNotes":"Reviewed current intent and validation.","acknowledgedConflictIds":[]}' \
  "${POLICY_API}/policies/${POLICY_ID}/approve"

Return 200 with a policy summary, policy ETag, and current draft validator where applicable. Relevant response fields include:

{
  "policy": {
    "id": "policy-1",
    "status": "approved",
    "policyState": "approved",
    "governedRevision": 1,
    "hasOpenDraft": false,
    "draftState": null
  }
}

Policy revalidates dependencies before creating the governed revision. Changed or unacknowledged findings can block approval. Approval queues durable asynchronous publication. It does not prove publication, consumer receipt, or downstream protection. Inspect the independent enforcementState and operation evidence. Operation inspection requires policy:audit. Approval capability alone does not grant that access.

POST /policies/{policy_id}/archive

Request removal of the approved policy’s published configuration. Use GET /policies/{policy_id}/operations to monitor that background removal. Confirm that the policy has a governed revision before selecting archive. Draft cancellation is a separate operation and does not withdraw governed protection. Require policy:archive. Send the latest policy ETag through If-Match, never the draft token.

The archive request accepts this reason field:

FieldTypeRequirement
reasonStringSupply 1–512 characters with nonblank trimmed text.
curl --fail-with-body -X POST \
  -H "@${POLICY_AUTH_HEADER:?Complete authentication setup}" \
  -H "Content-Type: application/json" \
  -H "If-Match: ${POLICY_ETAG}" \
  --data '{"reason":"Approved retirement of the governed policy."}' \
  "${POLICY_API}/policies/${POLICY_ID}/archive"

Return 200 with a policy summary, deploymentId, and integer generation. The summary identifies the independent archiving protection state. Do not interpret the compatibility archive status as completed withdrawal. Record the returned generation for subsequent archive evidence or authorized retry. Use deploymentId to select the operation and generation to distinguish its work from later attempts.

Response Codes and Concurrency

The table lists possible failure status codes for each lifecycle operation:

OperationFailure Statuses
SubmitReturn 400, 401, 403, 404, 409, 412, 422, 428, or 500.
Request changesReturn 401, 403, 404, 409, 422, or 428.
ApproveReturn 400, 401, 403, 404, 409, 412, 422, 428, or 500.
ArchiveReturn 400, 401, 403, 404, 409, 412, 422, 428, or 500.

401 identifies missing trusted identity. 403 identifies missing authority. 404 identifies missing policy or draft context. 428 identifies a missing required token. Draft commands normally return 409 for a changed head. Request-changes also returns 409 when the head is not in review. Submit and approve return 400 for a non-draft token. Concurrent policy/revision persistence can produce 412. Archive returns 400 for malformed policy tokens and 412 for stale versions.

409 can also mean invalid lifecycle state, blocking conflicts, or changed dependencies. 422 can contain body-schema errors or sanitized validation findings. Compile, submit, and approval validation failures can expose a supportReference. Refer to error handling for envelope variations.

These commands do not implement a general Idempotency-Key contract. After a timeout, inspect current policy and history before deciding whether to repeat. After a conflict, review changed evidence before issuing another command. Do not apply a fresh token to an old, unreviewed decision.

Last modified : November 03, 2026