---
title: "Undo a changeset"
description: "Replays a bundle's operations backwards, through the same permission compiler as any other write, so undoing a delete re-creates the row only if you could have created it."
canonical: "https://gtable.app/docs/builder-api/changesets/revert"
updated: "2026-10-05"
---

# Undo a changeset

`POST https://studio.gtable.app/v1/apps/{appId}/changesets/{changesetId}/revert`

Replays a bundle's operations backwards, through the same permission compiler as any other write, so undoing a delete re-creates the row only if you could have created it.

An update puts back ONLY the fields it changed, so somebody else's edit to another field of the same record survives; if they changed one of the SAME fields since, this refuses and says whose, and `confirm: true` overwrites theirs anyway. The revert is itself recorded, so reverting a revert is just undo again. Only a bundle of record creates, edits and deletes can be undone, and the list marks each one `revertible`: a comment, a saved view, a page or a change to the app's SHAPE is refused up front with the reason, because putting a definition back would run its migration in reverse, and a column that returns is a column whose contents went. A deleted field or table, and a column a type change converted, is put back from the trash instead (trash.restore), values and all. Every row it can put back is undone in ONE transaction, and a row deleted since is listed in `skipped` rather than failing the rest.

Requires the `records:write` scope. Operation `changesets.revert`. MCP tool `changesets_revert`. CLI, once published: `gtable changesets revert`.

## Path parameters

| Name          | Type   | Required | Description |
| ------------- | ------ | -------- | ----------- |
| `appId`       | string | yes      |             |
| `changesetId` | string | yes      |             |

## Headers

| Name              | Type   | Required | Description                                                                                                                                                                                                                                                        |
| ----------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Idempotency-Key` | string | no       | Any unique string. Sending the same key with the same request again returns the first response (marked `Idempotency-Replayed: true`) instead of running it twice. Reusing it for a different request is refused with 409. Kept for 24 hours. Up to 255 characters. |

## Request body

| Field     | Type    | Required | Description |
| --------- | ------- | -------- | ----------- |
| `confirm` | boolean | no       |             |
