# Correct or remove a message

Edit a message to correct its body, or delete it to remove its content from the conversation. An edit saves the previous body as a revision. Deletion leaves an empty placeholder and removes the revisions.

## Before you start

- A message id of your product. Read one back with [`support_message_get`](/reference/mcp-tools/support_message_get) or [`support_message_list`](/reference/mcp-tools/support_message_list).
- The identity that created the message, for the two operations that act only on your own. Ownership is the Lepsto identity Support recorded when the message was written — not `authorAgentId` and not `authorExternalId`, which are values the caller passed in.
- Admin rights on the product, for the two admin operations.

MCP calls use the authorizing identity’s permissions. Use a product-scoped token with **write** access for your own-message operations and **admin** access for the admin operations below. Replace `456ae172…` in the examples with your full message id.

## Who may use which tool

| Tool | Level | Which message |
|---|---|---|
| [`support_message_update`](/reference/mcp-tools/support_message_update) | write | Only one your own identity created |
| [`support_message_delete`](/reference/mcp-tools/support_message_delete) | write | Only one your own identity created |
| [`support_message_delete_any`](/reference/mcp-tools/support_message_delete_any) | admin | Any message of the product, inbound included |
| [`support_message_revisions_list`](/reference/mcp-tools/support_message_revisions_list) | admin | The edit history of any message of the product |

Messages created before creator identities were recorded, and messages submitted through the [public HTTP API](/ship/support/public-api), have no creator identity. They cannot be edited. An admin can remove them with `support_message_delete_any`.

All four operations require the authenticated API; none accepts a product public key.

## Edit a message you posted

1. Call `support_message_update` with the message id and the replacement body.

   ```json
   {
     "id": "456ae172…",
     "body": "Thanks for the report. Which browser are you on?"
   }
   ```

2. Read the result. `body` is the new text and `editedAt` carries the moment of the edit.

`body` replaces the text verbatim and allows at most 50,000 characters. An empty string is accepted only when the message already has an uploaded attachment. Without one, the operation returns `400 message_needs_body_or_attachment`.

An edit leaves direction, visibility, authorship, attachments, and the thread’s `lastReplyAt` unchanged. Resending the existing body is a no-op: it creates no revision, timestamp change, or event.

Check these failures before retrying:

| Status | When |
|---|---|
| `403` | The message belongs to another identity, or to nobody |
| `409` | The message is already deleted |
| `404` | The message belongs to another product |

**Check the result.** Read the message back with `support_message_get`. `body` is the new text and `editedAt` is no longer `null`.

## Remove a message

1. Call `support_message_delete` for a message your identity wrote, or `support_message_delete_any` for any message of the product.

   ```json
   { "id": "456ae172…" }
   ```

2. Read the result. `deletedAt` is set, `body` is `""` and `attachments` is `[]`.

Deletion keeps a placeholder and makes these changes together:

- `body` becomes `""`;
- `attachments` becomes `[]`, and those files are no longer served;
- `deletedAt` is set, with the identity that deleted it;
- every revision of the message is destroyed in the same transaction, so a deleted body does not survive in the edit history.

Deleting a message that is already deleted succeeds again and publishes no second event. Deleting does not change the thread's status.

Deleting a **public** message recalculates the thread's `lastReplyAt` in the same transaction: it becomes the creation time of the newest public message that is not deleted, or `null` if none are left.

`support_message_delete` returns `403` for a message another identity created. With admin access, `support_message_delete_any` can remove any product message, including inbound and unowned messages.

**Check the result.** List the conversation with `support_message_list`. The message is still there, with `body: ""`, `attachments: []` and a `deletedAt` timestamp.

## Render a deleted or edited message

Keep deleted messages in their conversation position and show a placeholder such as "Message removed". Use `editedAt` to label edited messages.

`support_message_get` and `support_message_list` return the same message shape. Webhooks identify the changed message so you can read its current state.

## Read the edit history

1. With admin access, call `support_message_revisions_list` with the message id.
2. Read revisions newest first. Each contains a previous body, the identity that replaced it, and the time of replacement.

```json
{ "id": "456ae172…" }
```

**Check the result.** An unedited message has no revisions. After an edit, its previous body is listed; after deletion, the list is empty because deletion removes every revision.

## What your integration hears

A public-message edit emits `support.message.updated`; deletion emits `support.message.deleted`. Both apply to either direction and either author type, and neither includes message bodies. The deletion event adds `scope: "own"` or `scope: "any"` to identify the delete operation. Internal notes emit neither event. See [Receive Support events](/ship/support/webhooks#the-seven-events).

## Where to go next

- [Threads and messages](/ship/support/threads-and-messages): what a message carries in the first place.
- [Receive Support events](/ship/support/webhooks): the payloads these two events send.
- [Tools, SDK and errors](/ship/support/tools-and-errors): every tool named here, and how it is called.
