---
title: "Undo an action of the Editor Assistant | GPT-Video API"
description: "Puts the project back as it was before one action of a turn, and returns the turn."
url: "https://www.gpt-video.com/developers/api/undo-assistant-action"
operation: "undo_assistant_action"
method: "POST"
path: "/v1/assistant/turns/{turnId}/actions/{actionId}/undo"
scope: "clips:write"
---

Do not assume endpoints have parameters other than the ones explicitly specified.

# Undo an action of the Editor Assistant

Operation id `undo_assistant_action`. Request `POST /v1/assistant/turns/{turnId}/actions/{actionId}/undo`.

Puts the project back as it was before one action of a turn, and returns the turn.

Beta. This endpoint is supported and can gain new fields. If a change would break your code, we tell you before it takes effect and list it in the changelog.

## About

Call this to take back one change the Editor Assistant made, named by the id in the actions of its turn. Only an action with undoable set to true can be undone, and only while nothing changed after it: when the project changed since, the call answers CONFLICT and the way forward is a new change. An action that added a clip to an edit gives its credits back when it is undone, unless the edit was exported after it; creditsReturned says how many. Undoing an action that is already undone answers the turn as it is, with creditsReturned 0.

## Example use

A user sees that one action of the Editor Assistant went too far, such as a cut that removed a whole answer. The tool sends the id of that action, and the project goes back to how it was before it.

## Endpoint

```text
POST https://api.gpt-video.com/v1/assistant/turns/{turnId}/actions/{actionId}/undo
```

- Scope `clips:write`.
- Rate limit 60 requests a minute for each key and 120 for each account, shared by every `write` call. See [rate limits](/developers/rate-limits.md).
- `Idempotency-Key` is optional.

## Parameters

### Path

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `turnId` | string | Required | The id of the turn, as create_assistant_turn (`POST /v1/projects/{projectId}/assistant/turns`) or list_assistant_turns (`GET /v1/projects/{projectId}/assistant/turns`) returned it. It starts with agm_. Matches `^agm_[0-9a-f]{20}$`. |
| `actionId` | string | Required | The id of one action of the turn, from its actions. It starts with tc_. Matches `^tc_[0-9a-f]{20}$`. |

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | Optional | Send the same key on every retry of this request. From 1 to 255 visible characters, such as a UUID. See [idempotency](/developers/pagination-and-idempotency.md). |

## Request

Undo an action.

```bash title="curl"
curl -X POST "https://api.gpt-video.com/v1/assistant/turns/agm_1e3d5feef4076b4329cf/actions/tc_6c98ac1c068fc322b284/undo" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY"
```

```ts title="TypeScript"
const res = await fetch("https://api.gpt-video.com/v1/assistant/turns/agm_1e3d5feef4076b4329cf/actions/tc_6c98ac1c068fc322b284/undo", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
  },
});
const data = await res.json();
console.log(data);
```

```python title="Python"
import os

import requests

r = requests.post(
    "https://api.gpt-video.com/v1/assistant/turns/agm_1e3d5feef4076b4329cf/actions/tc_6c98ac1c068fc322b284/undo",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
    },
)
data = r.json()
print(data)
```

```json title="MCP (Full)"
{
  "method": "tools/call",
  "params": {
    "name": "undo_assistant_action",
    "arguments": {
      "turnId": "agm_1e3d5feef4076b4329cf",
      "actionId": "tc_6c98ac1c068fc322b284"
    }
  }
}
```

## Response

A successful call answers HTTP 200. Returns a [Assistant turn object](/developers/objects.md#assistant-turn) in `turn`.

### Fields to check

| Name | Type | Description |
| --- | --- | --- |
| `turn.id` | string | The turn id. It starts with agm_. |
| `turn.status` | string | queued and running are still working; done, failed and cancelled are final. |
| `turn.actions[].id` | string | The action id. It starts with tc_. |
| `turn.actions[].status` | string |   |
| `turn.jobId` | string or null | The job that runs the turn; null once it is gone. |

### Response example

```json title="HTTP 200"
{
  "turn": {
    "id": "agm_1e3d5feef4076b4329cf",
    "projectId": "prj_b9c1f9c7873dcef51a57",
    "status": "done",
    "message": "Make the captions bolder.",
    "reply": "I switched the captions to the bold karaoke style.",
    "outcome": "done",
    "question": null,
    "options": [],
    "actions": [
      {
        "id": "tc_6c98ac1c068fc322b284",
        "tool": "set_captions",
        "status": "undone",
        "summary": "Captions: bold karaoke",
        "undoable": false,
        "creditsReturned": 0
      }
    ],
    "jobId": "job_0724f7cc56c41f889a0c",
    "errorMessage": null,
    "createdAt": "2026-08-31T22:31:00.000Z",
    "finishedAt": "2026-08-31T22:32:00.000Z"
  },
  "creditsReturned": 0
}
```

**All response fields**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `turn` | Assistant turn object | Required | Described in [Assistant turn object](/developers/objects.md#assistant-turn). |
| `creditsReturned` | integer | Required | The credits this call gave back; 0 when the action bought nothing or was already undone. At least 0. |

**More examples**

#### An action that is already undone

`POST /v1/assistant/turns/agm_1e3d5feef4076b4329cf/actions/tc_6c98ac1c068fc322b284/undo`

```json title="HTTP 200"
{
  "turn": {
    "id": "agm_1e3d5feef4076b4329cf",
    "projectId": "prj_b9c1f9c7873dcef51a57",
    "status": "done",
    "message": "Make the captions bolder.",
    "reply": "I switched the captions to the bold karaoke style.",
    "outcome": "done",
    "question": null,
    "options": [],
    "actions": [
      {
        "id": "tc_6c98ac1c068fc322b284",
        "tool": "set_captions",
        "status": "undone",
        "summary": "Captions: bold karaoke",
        "undoable": false,
        "creditsReturned": 0
      }
    ],
    "jobId": "job_0724f7cc56c41f889a0c",
    "errorMessage": null,
    "createdAt": "2026-08-31T22:31:00.000Z",
    "finishedAt": "2026-08-31T22:32:00.000Z"
  },
  "creditsReturned": 0
}
```

#### An action that does not exist

`POST /v1/assistant/turns/agm_1e3d5feef4076b4329cf/actions/tc_b38d81a939ed88a2b178/undo`

```json title="HTTP 404"
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Action tc_b38d81a939ed88a2b178 not found",
    "hint": "Check the id. An id that belongs to another account is not found either.",
    "requestId": "req_1e6b9d3f7a2c4e8b0d5f3a68"
  }
}
```

## Errors

| Code | Status | When | What to do |
| --- | --- | --- | --- |
| [`NOT_FOUND`](/developers/errors.md#NOT_FOUND) | 404 | An action that does not exist | Change the request, then send it again. |
| [`CONFLICT`](/developers/errors.md#CONFLICT) | 409 | The project changed after the action, or the action saved or removed a note, which only the GPT-Video app can undo. The message says which one. | Read the resource again, then decide. Do not send the same request again. |
| [`NOT_READY`](/developers/errors.md#NOT_READY) | 409 | See the error reference. | Wait for Retry-After, then send the same request again. |

Every call can also answer these errors. [`VALIDATION_FAILED`](/developers/errors.md#VALIDATION_FAILED), [`UNKNOWN_PARAMETER`](/developers/errors.md#UNKNOWN_PARAMETER), [`UNAUTHORIZED`](/developers/errors.md#UNAUTHORIZED), [`SCOPE_MISSING`](/developers/errors.md#SCOPE_MISSING), [`IDEMPOTENCY_IN_PROGRESS`](/developers/errors.md#IDEMPOTENCY_IN_PROGRESS), [`PAYLOAD_TOO_LARGE`](/developers/errors.md#PAYLOAD_TOO_LARGE), [`IDEMPOTENCY_KEY_REUSED`](/developers/errors.md#IDEMPOTENCY_KEY_REUSED), [`RATE_LIMITED`](/developers/errors.md#RATE_LIMITED), [`INTERNAL`](/developers/errors.md#INTERNAL), [`UNAVAILABLE`](/developers/errors.md#UNAVAILABLE).

## Cost

No credits are used. Undoing an action that added a clip gives its credits back.

## Related operations

- [`get_assistant_turn`](/developers/api/get-assistant-turn.md) (`GET /v1/assistant/turns/{turnId}`) Get an Editor Assistant turn
- [`create_assistant_turn`](/developers/api/create-assistant-turn.md) (`POST /v1/projects/{projectId}/assistant/turns`) Send a message to the Editor Assistant

## Questions

### Why does the undo answer CONFLICT?

The project changed after the action, and undoing it now would throw those changes away. Make the change you want with a new call instead.

### Do I get credits back?

Only for an action that added a clip to an edit, and only if the edit was not exported after it. creditsReturned says how many came back with this call.
