---
title: "Undo one change"
method: POST
path: "/api/v1/sites/{slug}/activity/{id}/revert"
tags: ["Draft & publish"]
---

# Undo one change

`POST /api/v1/sites/{slug}/activity/{id}/revert`

## Request

- Base URL: `https://api.dotsy.ai`
- URL: `https://api.dotsy.ai/api/v1/sites/{slug}/activity/{id}/revert`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer

Puts back the version each file had before this change, as a draft — publish to make it live. It works on a change that is still a draft and on one that is already published, and it never overwrites a later edit: a page edited since is skipped (`changed_since`) and the rest are still undone. Send `keys` to undo only some files of a change; omit it to undo all.

Some changes cannot be undone here: a page that was created and is live now (delete it instead), a delete that also removed routes, the site brief, and a change that touched too many files. The undo is recorded as a `revert` event. An agent on "Drafts only" AI access may use this; one on "Read only" may not.

## Path parameters

- `slug` string, required
- `id` string, required

## Request body

- ActivityRevertRequest
  - `keys` string[]: Undo only these keys of the change. Default: every key.
  - `reason` string: Why — shown next to 'Reverted by …'. Visible to everyone on the site.

## Response `200`

At least one file was put back (staged as a draft).

- ActivityRevertResult
  - `reverted` string[], required: Content keys put back. They are staged as a draft — publish to make them live.
  - `skipped` object[], required: Keys left alone. `changed_since`: the page was edited after this change, so undoing it would overwrite the newer edit.
    - `key` string, required
    - `reason` union, required
      - 'changed_since'
      - 'published_creation' | 'deleted_with_routes' | 'brief' | 'truncated' | 'already_reverted' | 'not_content': Why a change cannot be undone here. `published_creation`: it created a page that is live now (delete the page instead). `deleted_with_routes`: it deleted a page and its routes. `brief`: the site brief has its own rules. `truncated`: too many files. `already_reverted`: it was undone. `not_content`: this event changed no page.
  - `eventId` string, nullable, required: The id of the new `revert` event when at least one file was written back. Null when the audit insert failed, or when nothing was written (every key was already at the requested version — the source change may still be marked reverted).
  - `warnings` string[]: Non-blocking notes about tags that will not compose, one per problem, each as `<key>: <code> — <what to change>`. Codes: `fragment_unclosed`, `fragment_bad_name`, `fragment_full_document`, `fragment_self_reference`, `fragment_attr_hyphen`, `legacy_paige_tag`, `layout_missing_content`, `unknown_dotsy_syntax`. The write still happened. At most 50 are listed.

## Other responses

- `400`: The body is not valid (`invalid_body`), or `keys` names a file that is not part of this change (`invalid_keys`).
- `401`: Missing or invalid credentials.
- `403`: The key or token cannot edit this site (viewer role, or AI access set to read only).
- `404`: No such site, or no such event (`activity_not_found`).
- `409`: Nothing was undone: every file was edited since (`activity_change_conflict`, with `conflicts`), the draft is busy (`draft_busy`) or not readable yet (`draft_not_visible_yet`) — retry — the site backend changed (`placement_version_conflict`), or this storage arm cannot undo on the projection draft lane (`activity_revert_unsupported`, do-sqlite sites).
- `410`: The old version of a file is no longer kept (`activity_version_gone`). Nothing was changed.
- `422`: This change cannot be undone here (`activity_revert_blocked`, with `reason`).

---

[API](https://skmtc.dev/dotsy/apis/dotsy-api.md) · [All operations](https://skmtc.dev/dotsy/apis/dotsy-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dotsy/apis/dotsy-api/revisions/4272ed3b85d7?raw)
