> ## Documentation Index
> Fetch the complete documentation index at: https://docs.senderkit.com/llms.txt
> Use this file to discover all available pages before exploring further.

# messages

> Inspect message history from the terminal.

`senderkit messages` queries the [message](/concepts/messages) log — the durable
record of every send and its status. The CLI exposes the list endpoint with
filters and cursor pagination, paired with `--json` for piping into `jq`,
spreadsheets, or downstream alerting.

## `senderkit messages list`

List messages newest-first. With no flags, returns a recent page across all
channels and statuses.

```bash theme={null}
senderkit messages list [options]
```

### Options

<ParamField path="--limit <number>">
  Maximum messages to return (a positive integer). The server has its own
  default and maximum — see the [API Reference](/api-reference/introduction).
</ParamField>

<ParamField path="--cursor <string>">
  Pagination cursor. Use the `nextCursor` from a previous response to fetch the
  next page.
</ParamField>

<ParamField path="--status <string>">
  Filter by [status](/concepts/messages#the-message-lifecycle), e.g. `queued`,
  `rendered`, `sent`, `delivered`, `failed`, `opted_out`.
</ParamField>

<ParamField path="--channel <email|sms|push|web-push>">
  Filter by channel.
</ParamField>

<ParamField path="--template <slug>">
  Filter by template slug, e.g. `welcome`.
</ParamField>

<ParamField path="--metadata <json>">
  Filter by the [metadata](/cli/send) you attached at send time, as a JSON
  object — e.g. `'{"orderId":"ord_9"}'`. Every key/value pair must match.
</ParamField>

### Examples

```bash theme={null}
# Recent messages, table view
senderkit messages list

# Everything that failed, by email
senderkit messages list --status failed --channel email

# All sends of a specific template
senderkit messages list --template welcome --limit 100

# Filter by metadata attached at send time
senderkit messages list --metadata '{"orderId":"ord_9"}'

# Paginate
senderkit messages list --limit 50
senderkit messages list --limit 50 --cursor "msg_01HZ…"
```

Human output:

```
ID         STATUS     CHANNEL  TEMPLATE        TO                CREATED
msg_01HZ…  delivered  email    welcome         user@example.com  2026-05-28T10:14:02Z
msg_01HY…  failed     email    password-reset  jane@example.com  2026-05-28T10:13:55Z
next cursor: msg_01HX…
```

### Scripting with `--json`

`--json` emits the full SDK response — a `data` array and a `nextCursor`
string — which makes `jq` workflows clean:

```bash theme={null}
# Count failed messages in the latest page
senderkit messages list --status failed --json | jq '.data | length'

# Pull every recipient that bounced today
senderkit messages list --status failed --json | jq -r '.data[].recipient'

# Walk every page
cursor=""
while :; do
  page=$(senderkit messages list --limit 100 ${cursor:+--cursor "$cursor"} --json)
  echo "$page" | jq '.data[]'
  cursor=$(echo "$page" | jq -r '.nextCursor // empty')
  [ -z "$cursor" ] && break
done
```

## `senderkit messages get`

Fetch a single message by its public ID.

```bash theme={null}
senderkit messages get <id>
```

<ParamField path="id" required>
  Public message ID, e.g. `msg_01HZ…` — the `id` returned by
  [`send`](/cli/send) or a row from `messages list`.
</ParamField>

```bash theme={null}
senderkit messages get msg_01HZ…
```

```
id:        msg_01HZ…
status:    delivered
channel:   email
template:  welcome
recipient: user@example.com
openedAt:  2026-05-28T10:16:40Z
clickedAt: —
createdAt: 2026-05-28T10:14:02Z
```

Add `--json` for the full message object.

## `senderkit messages cancel`

Cancel a still-pending message. Only `scheduled` or `queued` messages are
cancelable — once a message has moved past that (e.g. `sent`), the server
returns a `409` and the command fails.

```bash theme={null}
senderkit messages cancel <id>
```

<ParamField path="id" required>
  Public message ID of a scheduled or queued message.
</ParamField>

```bash theme={null}
senderkit messages cancel msg_01HZ…
```

```
✓ Canceled msg_01HZ…
id:     msg_01HZ…
status: canceled
```

<Note>
  There's no live tail (`messages tail`) in the CLI. For real-time delivery
  monitoring, use the SSE stream (`GET /v1/messages?tail=1`) described in the
  [API Reference](/api-reference/introduction); from the terminal, poll
  `messages list` with a filter.
</Note>

<Warning>
  Messages are retained for [a limited window](/concepts/messages#retention) —
  3 days on Free, 14 days on Pro. If you need history beyond that, export with
  `--json` on a schedule and persist in your own system, correlating via the
  `metadata` you attached at send time.
</Warning>

<CardGroup cols={2}>
  <Card title="Messages" icon="list-check" href="/concepts/messages">
    The lifecycle and retention rules behind these records.
  </Card>

  <Card title="send" icon="paper-plane" href="/cli/send">
    Fire a send, then query its status here.
  </Card>

  <Card title="Sending" icon="paper-plane" href="/concepts/sending">
    Why a queued message hasn't been delivered yet.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    The list endpoint, status enum, and live tail stream.
  </Card>
</CardGroup>
