---
title: "Undo message"
method: POST
path: "/api/apps/{app_id}/chat/message/{message_id}/undo"
---

# Undo message

`POST /api/apps/{app_id}/chat/message/{message_id}/undo`

<Info>This API is in beta. Endpoints, fields, and behavior may still change, so avoid depending on it in production.</Info>

Rolls the app back to the [checkpoint](/developers/references/app-management/get-started/concepts#checkpoints) a message produced, undoing everything the AI did after it.

Pass the ID of the message you want to roll back to. Find it with [Read conversation messages](/api-reference/read-conversation-messages). Only a message that carries a `checkpoint_id` can be undone. The app's code goes back to that saved version.

This changes the app you are building, not the app your users see. Publish with [Deploy an app](/api-reference/deploy-an-app) to make the rollback live.

<Warning>The response includes fields beyond the ones documented here. Don't rely on undocumented response fields, as they can change at any time.</Warning>

## Path parameters

- `message_id` string, required — ID of the message to roll back to. Take it from [Read conversation messages](/api-reference/read-conversation-messages).
- `app_id` string, required — ID of the app whose AI chat this request acts on.

## Response `200`

Successful Response

- ChatTurnResponse — An app, with its conversation and build status.
  - `id` string, nullable — ID of the app.
  - `name` string, nullable — Display name of the app.
  - `status` AppStatusResponse — The app's current build status.
    - `state` 'ready' | 'processing' | 'error', required — Where the app is in its build lifecycle. Ready means idle with no build in progress, processing means the app is being generated or modified, and error means the last build failed. This tracks building, not publishing.
    - `details` string, nullable — Human readable note about the current state, such as what is being processed or why it failed, or `null` when there is nothing to report.
    - `request_id` string, nullable — ID of the request that last changed the status, or `null` if the status has never changed. Useful when reporting an issue.
    - `last_updated_date` string, date-time, nullable — Time the status was last updated, as a UTC timestamp in ISO 8601 format.
    - `error_source` string, nullable — Where the failure originated when `state` is `error`, or `null` otherwise. A value of `paywall` means the work was blocked because the app's workspace has no credits left.
    - `paywall_context` PaywallStatusContextResponse
      - `billing_organization_id` string, required — ID of the billing organization the paywall was evaluated against.
      - `user_id` string, required — ID of the user the paywall was evaluated for.
      - `evaluated_at` string, date-time, required — Time the paywall condition was evaluated, as a UTC timestamp in ISO 8601 format.
  - `conversation` ChatTurnConversation
    - `id` string, nullable — ID of the conversation.
    - `messages` ConversationMessageSummary[], nullable — The conversation's messages once the request finished, oldest first.
      - `id` string, nullable — ID of the message.
      - `role` 'user' | 'assistant' | 'system', nullable — Who produced the message. A `user` message is a prompt sent to the AI, an `assistant` message is the AI's reply, and a `system` message is a platform-generated note.
      - `content` string, nullable — Text of the message. Empty on assistant turns whose work is carried entirely by tool calls, and on internal diff messages.
      - `file_urls` string[], nullable — URLs of the files attached to the message, or `null` if it has none.
      - `hidden` boolean, nullable — Whether the message is internal and hidden from the chat in the app editor.
      - `checkpoint_id` string, nullable — ID of the [checkpoint](/developers/references/app-management/get-started/concepts#checkpoints) this message produced, or `null` if it produced none. Pass it as `checkpoint_id` to [Deploy an app](/api-reference/deploy-an-app) to deploy that version.
      - `tool_calls` ConversationToolCallSummary[], nullable — Tool calls the AI made on this message, or `null` on messages that made none. A call with `status` set to `waiting_for_user_input` is holding the turn open until it is answered.
        - `id` string, nullable — ID of the tool call. Pass it as `tool_call_id` to [Submit tool-call input](/api-reference/submit-tool-call-input) when `status` is `waiting_for_user_input`.
        - `name` string, nullable — Name of the tool the AI is calling.
        - `status` 'running' | 'success' | 'error' | 'stopped' | 'waiting_for_user_input', nullable — Where the tool call is. Either `running`, `success`, `error`, `stopped`, or `waiting_for_user_input`. The last one means the turn is paused until the call is answered.
        - `requires_user_input` boolean, nullable — Whether this tool call has to be approved or rejected before the turn can continue.
        - `arguments_string` string, nullable — What the AI asked the tool to do, as a JSON object encoded in a string. Parse it to see the arguments before answering a call that is waiting. On a call whose `requires_user_input` is `true` the value is complete rather than shortened, which is the case that matters, because approving without reading it is approving blind. On any other call it can be cut to the first 500 characters. The one exception either way is the browser-typing tools, `local_browser_type` and `local_browser_press_key`, which always replace what was typed with `[redacted]` so a password or one-time code is never returned, waiting or not. Approving one of those means approving a value you cannot see. It is an empty string on a tool call that takes no arguments.
      - `usage` MessageUsageSummary
        - `prompt_tokens` integer, nullable — Tokens the model read for this message, including the conversation history it was given.
        - `completion_tokens` integer, nullable — Tokens the model generated for this message.
        - `credits_charged` number, nullable — Credits charged for this message, or `null` if it was not billed.
      - `metadata` MessageMetadataSummary
        - `created_date` string, date-time, nullable — Time the message was created, as a UTC timestamp in ISO 8601 format.
        - `created_by_email` string, nullable — Email of the user whose turn produced the message, or `anonymous` on a message Base44 created with no user in context.

## Other responses

- `400` — The message has no checkpoint to roll back to.
- `401` — Missing or invalid credentials.
- `403` — You don't have access to this app.
- `404` — App, message, or checkpoint not found.
- `409` — The app is busy with another operation that blocks the rollback, or the request is scoped to a feature branch. A rollback restores a checkpoint, which is app-wide, so it can only run on the main branch.

---

[API](https://skmtc.dev/adexad/apis/base44-app-management-api.md) · [All operations](https://skmtc.dev/adexad/apis/base44-app-management-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/adexad/base44-app-management-api/revisions/7f5ce8287501/schema)
