POST /api/v1/programs/{programId}/archive
Hides the program from learner lists and switchers and refuses new learner reads and actions, including direct links and agent calls. Enrollments, progress, submissions and history are preserved. Staff can still consult authorized history. Use Restore a program to restore its previous status.
It is a verb rather than a PATCH because it is not a field: it opens a period
boundary, carries a reason, and writes its own event.
| Role in the organization | This endpoint |
|---|---|
OWNER | Allowed |
ADMIN | Allowed |
MEMBER | Refused |
| Requirement | Rule for this endpoint |
|---|---|
| Business role | None — composing content is an organization-role decision |
| Resource scope | Program of the school attached to the API key |
| Resource state | An already archived program is refused unless this is an idempotent replay |
| Parameter | Type | Required | Description |
|---|---|---|---|
programId | UUID | yes | Program visible from the key's school |
| Header | Required | Description |
|---|---|---|
x-api-key | yes | API key created for this school |
Idempotency-Key | yes | Stable key for this archival |
X-Correlation-Id | no | Caller correlation id, returned or generated |
| Field | Type | Required | Nullable | Description |
|---|---|---|---|---|
effectiveAt | ISO 8601 string | no | no | Historical effective date. Defaults to now; access stops when the command is applied |
reason | string | no | yes | Up to 500 characters, kept in the program history |
effectiveAt is an input, not a derived value: the moment the row is
written is not the moment the archival takes effect, and backdating a closure
that already happened is the normal case.
{
"effectiveAt": "2026-08-31T22:00:00.000Z",
"reason": "Replaced by the 2027 edition."
}curl -X POST "$COHORTE_API_BASE_URL/api/v1/programs/$PROGRAM_ID/archive" \
-H "x-api-key: $COHORTE_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H 'Content-Type: application/json' \
-d '{"reason":"Replaced by the 2027 edition."}'200 OK — the program, now archived for a new command. An idempotent replay returns its current status, which may have been restored.400 Bad Request — missing Idempotency-Key, invalid JSON, or an invalid date.401 Unauthorized — the key is missing, invalid, or no longer attached to a member.403 Forbidden — the bearer is not OWNER or ADMIN of this school, or the program is already archived.404 Not Found — the program is unknown or belongs to another school.Identical to Read a program, with status
archived after a new command, or its current status on replay, plus replayed.
{
"success": true,
"replayed": false,
"data": {
"id": "9f2c0a1e-4b7d-4c1a-9e3f-2a6b8c0d1e2f",
"name": "Agentic AI Developer",
"slug": "agentic-ai-developer",
"description": "Twelve weeks to ship agents in production.",
"transformation": "Ship one agent to production every week.",
"status": "archived",
"unlockMode": "sequential",
"createdAt": "2026-09-01T09:00:00.000Z",
"updatedAt": "2026-09-04T17:12:00.000Z"
},
"correlationId": "0f6b1d92-5c3e-4a8b-9d71-3e2f4a6b8c10"
}program.archived event are written in
one transaction.New media authorizations are refused. Already issued signed links remain usable until their expiry; public external URLs and downloaded copies cannot be revoked. Requests already authorized may finish. Billing and enrollment dates are unchanged.