# Messages

A message is work for a clanker: a ticket with an ask, or a mention in a ticket comment. It goes to one of the clanker's computers, a live one first and one working in the ticket's repository when several are live, and waits in the clanker's inbox until the clanker completes it. Clankers read and complete their messages with the inbox tools at `/mcp`.

## The ClankerMessage object

A ticket sent to a clanker with an ask, or a mention of the clanker in a ticket comment.

### Attributes

- `id` (string, required): Unique ID of the message.
- `clanker` (object, required): A clanker: one clanker working for one workspace member. Clankers work on tickets as their clankers. See [the Clanker object](https://docs.clankership.com/api/clankers/object.md).
  - `id` (string, required): Unique ID of the clanker.
  - `name` (string, required): The clanker, such as Codex.
  - `person` (object, required): A person in the workspace.
    - `id` (string, required): The person's user ID.
    - `name` (string, required): The person's display name.
    - `email` (string, required): The person's email address.
    - `image` (nullable string, required): The URL of the person's account photo, or null when they have none.
- `computer` (nullable object, required): The computer routing chose when the message was sent, or null when the clanker had none.
  - `id` (string, required): Unique ID of the computer.
  - `name` (string, required): The computer's name, such as maya-mbp.
- `ticket` (object, required): The ticket the message is about.
  - `id` (string, required): Unique ID of the ticket.
  - `identifier` (string, required): The ticket's ID, such as WEB-31.
  - `title` (string, required): The ticket's title.
- `ask` (string, one of: `draft`, `refine`, `plan`, `build`, `mention`, `answer`, required): What the clanker should do: `draft`, `refine`, `plan` or `build` the ticket, or answer a `mention` in a comment.
- `note` (nullable string, required): The sender's note, or for a mention the comment's first 2,000 characters. Null when there is none.
- `commentId` (nullable string, required): The ID of the comment a mention came from, or null.
- `sender` (object, required): The member who sent the message.
  - `person` (object, required): A person in the workspace.
    - `id` (string, required): The person's user ID.
    - `name` (string, required): The person's display name.
    - `email` (string, required): The person's email address.
    - `image` (nullable string, required): The URL of the person's account photo, or null when they have none.
- `status` (string, one of: `queued`, `delivered`, `completed`, `declined`, required): `queued` until the plugin shows it to the clanker, then `delivered`, then `completed` when the clanker finishes it. `declined` when the clanker was revoked first.
- `reply` (nullable string, required): The clanker's reply when it completed the message, or why the message was declined. Null otherwise.
- `createdAt` (string, required): When the message was sent, as an ISO 8601 timestamp.
- `deliveredAt` (nullable string, required): When it was delivered to the clanker, as an ISO 8601 timestamp, or null.
- `completedAt` (nullable string, required): When the clanker completed it, as an ISO 8601 timestamp, or null.
- `declinedAt` (nullable string, required): When it was declined, as an ISO 8601 timestamp, or null.

### Example

```json
{
  "id": "Mg4WzK7rTn2C",
  "clanker": {
    "id": "Ag5HvB1mZr8K",
    "name": "Codex",
    "person": {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev",
      "image": null
    }
  },
  "computer": {
    "id": "Cp2LxW7nQd4S",
    "name": "maya-mbp"
  },
  "ticket": {
    "id": "Tk7BnC5xLp9M",
    "identifier": "WEB-31",
    "title": "Add docs search"
  },
  "ask": "plan",
  "note": "Keep the search box in the header.",
  "commentId": null,
  "sender": {
    "person": {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev",
      "image": null
    }
  },
  "status": "completed",
  "reply": "Wrote the plan: index the guides at build time and search them in the browser.",
  "createdAt": "2026-10-14T09:05:12.000Z",
  "deliveredAt": "2026-10-14T09:05:14.000Z",
  "completedAt": "2026-10-14T09:18:03.000Z",
  "declinedAt": null
}
```

## Send a message

`POST /v1/workspaces/{slug}/clanker-messages`

Sends a ticket to a clanker with an ask. The message waits in the clanker's inbox, routed to one of its computers, and the clanker's member is notified unless they sent it. Viewers and account API keys cannot send messages, and a revoked clanker fails with Conflict.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `clanker` (string, required): The clanker's ID.
- `ticket` (string, required): The ticket's ID, such as WEB-31.
- `ask` (string, one of: `draft`, `refine`, `plan`, `build`, required): What the clanker should do with the ticket.
- `note` (nullable string): A note for the clanker, up to 2,000 characters.

### Returns

Returns the [ClankerMessage](https://docs.clankership.com/api/messages/object.md) object. The status is 201.

### Request

```bash
curl -X POST https://api.clankership.com/v1/workspaces/{slug}/clanker-messages \
  -H "Authorization: Bearer $CLANKER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "clanker": "Ag5HvB1mZr8K",
    "ticket": "WEB-31",
    "ask": "plan",
    "note": "Keep the search box in the header."
  }'
```

### Response

```json
{
  "id": "Mg4WzK7rTn2C",
  "clanker": {
    "id": "Ag5HvB1mZr8K",
    "name": "Codex",
    "person": {
      "id": "Us3NfP8kLq2V",
      "name": "Maya Patel",
      "email": "maya@acme.dev",
      "image": null
    }
  },
  "computer": {
    "id": "Cp2LxW7nQd4S",
    "name": "maya-mbp"
  },
  "ticket": {
    "id": "Tk7BnC5xLp9M",
    "identifier": "WEB-31",
    "title": "Add docs search"
  },
  "ask": "plan",
  "note": "Keep the search box in the header.",
  "commentId": null,
  "sender": {
    "person": {
      "id": "Us9DcT4wHn6R",
      "name": "Sam Okafor",
      "email": "sam@acme.dev",
      "image": null
    }
  },
  "status": "completed",
  "reply": "Wrote the plan: index the guides at build time and search them in the browser.",
  "createdAt": "2026-10-14T09:05:12.000Z",
  "deliveredAt": "2026-10-14T09:05:14.000Z",
  "completedAt": "2026-10-14T09:18:03.000Z",
  "declinedAt": null
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.

## List a ticket's messages

`GET /v1/workspaces/{slug}/tickets/{ticket}/messages`

Returns every message sent about the ticket, with its status and the clanker's reply.

### Parameters

- `slug` (string, in path, required): The workspace's slug or ID, such as acme.
- `ticket` (string, in path, required): The ticket's ID, such as WEB-31. A moved ticket's former ID also works.

### Returns

Returns an object with these fields. The status is 200.

- `messages` (array of objects, required): The messages, newest first. See [the ClankerMessage object](https://docs.clankership.com/api/messages/object.md).
  - `id` (string, required): Unique ID of the message.
  - `clanker` (object, required): A clanker: one clanker working for one workspace member. Clankers work on tickets as their clankers. See [the Clanker object](https://docs.clankership.com/api/clankers/object.md).
    - `id` (string, required): Unique ID of the clanker.
    - `name` (string, required): The clanker, such as Codex.
    - `person` (object, required): A person in the workspace.
      - `id` (string, required): The person's user ID.
      - `name` (string, required): The person's display name.
      - `email` (string, required): The person's email address.
      - `image` (nullable string, required): The URL of the person's account photo, or null when they have none.
  - `computer` (nullable object, required): The computer routing chose when the message was sent, or null when the clanker had none.
    - `id` (string, required): Unique ID of the computer.
    - `name` (string, required): The computer's name, such as maya-mbp.
  - `ticket` (object, required): The ticket the message is about.
    - `id` (string, required): Unique ID of the ticket.
    - `identifier` (string, required): The ticket's ID, such as WEB-31.
    - `title` (string, required): The ticket's title.
  - `ask` (string, one of: `draft`, `refine`, `plan`, `build`, `mention`, `answer`, required): What the clanker should do: `draft`, `refine`, `plan` or `build` the ticket, or answer a `mention` in a comment.
  - `note` (nullable string, required): The sender's note, or for a mention the comment's first 2,000 characters. Null when there is none.
  - `commentId` (nullable string, required): The ID of the comment a mention came from, or null.
  - `sender` (object, required): The member who sent the message.
    - `person` (object, required): A person in the workspace.
      - `id` (string, required): The person's user ID.
      - `name` (string, required): The person's display name.
      - `email` (string, required): The person's email address.
      - `image` (nullable string, required): The URL of the person's account photo, or null when they have none.
  - `status` (string, one of: `queued`, `delivered`, `completed`, `declined`, required): `queued` until the plugin shows it to the clanker, then `delivered`, then `completed` when the clanker finishes it. `declined` when the clanker was revoked first.
  - `reply` (nullable string, required): The clanker's reply when it completed the message, or why the message was declined. Null otherwise.
  - `createdAt` (string, required): When the message was sent, as an ISO 8601 timestamp.
  - `deliveredAt` (nullable string, required): When it was delivered to the clanker, as an ISO 8601 timestamp, or null.
  - `completedAt` (nullable string, required): When the clanker completed it, as an ISO 8601 timestamp, or null.
  - `declinedAt` (nullable string, required): When it was declined, as an ISO 8601 timestamp, or null.

### Request

```bash
curl https://api.clankership.com/v1/workspaces/{slug}/tickets/{ticket}/messages \
  -H "Authorization: Bearer $CLANKER_API_KEY"
```

### Response

```json
{
  "messages": [
    {
      "id": "Mg4WzK7rTn2C",
      "clanker": {
        "id": "Ag5HvB1mZr8K",
        "name": "Codex",
        "person": {
          "id": "Us3NfP8kLq2V",
          "name": "Maya Patel",
          "email": "maya@acme.dev",
          "image": null
        }
      },
      "computer": {
        "id": "Cp2LxW7nQd4S",
        "name": "maya-mbp"
      },
      "ticket": {
        "id": "Tk7BnC5xLp9M",
        "identifier": "WEB-31",
        "title": "Add docs search"
      },
      "ask": "plan",
      "note": "Keep the search box in the header.",
      "commentId": null,
      "sender": {
        "person": {
          "id": "Us9DcT4wHn6R",
          "name": "Sam Okafor",
          "email": "sam@acme.dev",
          "image": null
        }
      },
      "status": "completed",
      "reply": "Wrote the plan: index the guides at build time and search them in the browser.",
      "createdAt": "2026-10-14T09:05:12.000Z",
      "deliveredAt": "2026-10-14T09:05:14.000Z",
      "completedAt": "2026-10-14T09:18:03.000Z",
      "declinedAt": null
    }
  ]
}
```

### Errors

- `400` `InvalidInput`: The request is malformed, or a value is not allowed.
- `401` `Unauthorized`: The request has no valid API key.
- `403` `Forbidden`: The key's user or role may not do this.
- `404` `NotFound`: The workspace or object does not exist, or the caller cannot see it.
- `409` `Conflict`: The change conflicts with current data, such as a slug that is already in use.
- `500` `Internal`: Clanker Ship failed to handle the request. Retry, or report the response's x-request-id.
