# Needs reply feed (/reference/needs-reply-feed)

Which conversations entered, returned to, or were revised in Needs reply.

## List Needs reply changes

`GET https://api.meetwillow.cx/api/v1/inbox/changes`

Requires `inbox:read` on an API key; a sign-in session or an MCP client is refused with `403` `An API key is required`. tRPC `context.inbox.changes`, with an API key only. No MCP tool. Only owners and admins can add `inbox:read` to a key.

Reports which conversations entered, returned to, or received a new customer message in the inbox's Needs reply list. Poll every few minutes with the stored cursor; each poll returns only what changed since the last. `GET /tickets` is ordered by latest message, so it misses a conversation that comes back without one: a late classification, a restore, or mail filed back into the inbox. The feed only reports; it never drafts, assigns or sends.

A poll that timed out can be repeated: the same cursor returns the same page. Skip any `conversationId` and `inputRevision` pair you have already handled.

- Leaving Needs reply is not reported. Read the ticket before acting on an old entry.
- A conversation that leaves and comes back between polls with no new customer message produces no entry, and one that enters and leaves between polls produces none.
- Each poll checks the whole organization, whatever the key's connection access; a key limited to some connections still sees only their conversations.

A `400` `Invalid cursor` means the cursor was not issued to your organization: start again without `cursor`.

### Parameters

- `limit` (query, integer): Page size, 1 to 500.
- `cursor` (query, string): nextCursor from the previous poll. Leave it out to read the feed from its start: every entry for the mailboxes you may read, including conversations that have since left Needs reply.

### Response

object

- `items` (object[]): Entries after the cursor, by sequence. Entries never change, and the same cursor always returns the same page.
  - `sequence` (string): The entry's position in the feed, a whole number as decimal text. Always increasing.
  - `conversationId` (string): The conversation. Its ticket, if it has one, carries the same conversationId in GET /tickets.
  - `inputRevision` (integer): Goes up by one with each new customer message in the conversation. conversationId plus inputRevision is the identity of a piece of work.
  - `reason` (`entered` | `returned` | `revised`): entered (in Needs reply for the first time the feed has seen), returned (had left Needs reply and is back: judged late, restored, filed back into the inbox or reopened) or revised (stayed in Needs reply and the customer wrote again).
  - `recordedAt` (string): When a poll noticed the change (ISO 8601), not when the change happened.
- `nextCursor` (string): Always present. Store it once the page is handled and send it as cursor on the next poll. Equal to the cursor you sent when nothing changed.
- `hasMore` (boolean): True when more entries are ready: request the next page straight away.

### Errors

`400` Bad request, `401` Unauthorized, `403` Forbidden, `500` Internal server error.

## Error body

- `code` (string): The error code: BAD_REQUEST or PARSE_ERROR (400), UNAUTHORIZED (401), FORBIDDEN (403), NOT_FOUND (404), UNSUPPORTED_MEDIA_TYPE (415), TOO_MANY_REQUESTS (429) or INTERNAL_SERVER_ERROR (500).
- `message` (string): What went wrong. A 401 does not say which part of the key failed; a 403 names what is missing, such as the permission; every 5xx says Request failed.
- `issues` (object[], optional): For the message Input validation failed, each problem with the input.
