
# Restore a configuration revision

`POST /v1/config-revisions/{revision_id}:restore` · permissions `config:write`, `config:read` and the read permissions of the revision's kinds

Creates a new [plan](../config-plans/create.md) that undoes the apply that stored the revision. Nothing changes yet: review the plan, then apply it with [`POST /v1/config-plans/{plan_id}:apply`](../config-plans/apply.md). Rolling back goes through the same plan → apply path as any other change, so the same staleness check, deletion confirmation, secret and permission rules apply.

The plan's target is the revision:

- Resources the apply updated or deleted get back the spec they had before the apply. Deleted resources are created again.
- Resources the apply created are deleted. In that case the plan has `prune: true` and covers every current resource of the revision's kinds; resources the apply did not touch are planned as `no_op`, so only the created ones are deleted. Applying it needs `confirm_deletions`, as for any plan with deletions.
- Kinds the revision does not cover are not touched.

Revisions contain no secret values. A connection that is created again needs its client secret when the plan is applied (`requires_secret`, a `secret_required` warning). A secret changed by the original apply is not restored.

## Request

| Parameter | Description |
|---|---|
| `revision_id` | The revision id, `cfgr_…`, from [the revision list](list.md). |

The request has no body. An empty body, `{}` or `null` is accepted; any field is rejected. Send an `Idempotency-Key` header to make retries safe.

## Response

`201 Created` with `Location: /v1/config-plans/{plan_id}` and `Cache-Control: no-store`. The body is a plan, in the same form as [the response of plan creation](../config-plans/create.md). The plan is valid for 1 hour and counts toward the environment's plan rate limit and quota. The `config_plan.created` entry in the environment's management log records that the plan came from this revision.

## Errors

| HTTP | code | When |
|---|---|---|
| 400 | `malformed_request`, `unknown_field` | The body is not empty, `{}` or `null`. |
| 401 | `unauthenticated` | The credential is missing, invalid or revoked. |
| 403 | `insufficient_permissions` | The credential lacks a permission the plan needs; `required_permissions` lists all of them. |
| 404 | `not_found` | The revision does not exist, belongs to another environment or is older than 90 days. |
| 413 | `config_document_too_large` | The plan's document would exceed 5,000 resources or 10 MiB. |
| 422 | `validation_failed` | The revision can no longer be restored; see below. `errors[].pointer` points into the revision (`/revision/<kind>/<key>/...`). |
| 429 | `rate_limited` | The plan rate limit or the environment's plan quota was reached; retry after the `Retry-After` period. |
| 503 | `service_unavailable` | Plan capacity is full or a dependency is temporarily unavailable; retry after the `Retry-After` period. |

| `errors[].code` | Meaning |
|---|---|
| `not_restorable` | `/revision_id`: the revision covers a kind that no longer exists. |
| `invalid` | A stored spec no longer matches the current configuration schema. |
| `unresolved_reference` | A restored resource refers to a `key` that will not exist. |
| `key_in_use` | The `key` now belongs to an application or API that configuration does not manage. |
| `still_referenced` | `/revision/created`: a resource the apply created is still referenced by a resource that stays. |

## Example

```bash
curl -X POST "https://api.eu.keenauth.com/v1/config-revisions/cfgr_01m4qpqtywfs7930tb6kqn5rc5:restore" \
  -H "Authorization: Bearer $KEENAUTH_SECRET_KEY" \
  -H "Idempotency-Key: $(uuidgen)"

keenauth config revisions restore cfgr_01m4qpqtywfs7930tb6kqn5rc5
keenauth config apply cfgp_01m4qpqtywfs7930tb6kqn5rc5
```
