# Events with cademi listen

`cademi listen` streams the public events of your account to the terminal in real time. With `--forward-to`, it also delivers each event to an application on your machine, with the same body and signature as a webhook delivery. Use it to build and test your webhook receiver before you register a public endpoint.

## Start listening

```sh
cademi listen
```

The CLI creates a temporary event stream for the current credentials, connects to it, and prints its ID. It then prints one line per event: the local time, the event type, the event ID, and the ID of the resource the event is about. Press Ctrl-C to stop. The CLI then revokes the temporary event stream.

The credentials need `event_streams.manage` to create and revoke the event stream, `event_streams.read` to connect to it, and `events.read`. You receive only the events within the scope of `events.read`. See [Event streams](https://cademi.dev/api/event-streams.md) for how event streams work and the [Event catalog](https://cademi.dev/api/events.md) for the event types.

### Filter events

```sh
cademi listen --events product.created,product.updated
cademi listen --resources product,user
```

`--events` takes event types from the catalog, and `--resources` takes resource types. Both accept a comma-separated list or a repeated flag. An unknown event type is rejected with `422 validation_failed`.

### Starting point

A new event stream starts at the moment you run `cademi listen`, so you receive only newer events. `--replay` also delivers the retained events from before that moment, oldest first, and then continues with new ones. Events are retained for 30 days.

Expect a delay of a few seconds between an event and its line in the terminal. See [Event streams](https://cademi.dev/api/event-streams.md#sse-transport).

## Forward events to your application

```sh
cademi listen --forward-to localhost:3000/webhooks/cademi
```

For every event, the CLI sends a `POST` to the URL, with the webhook payload as the body and the webhook headers, signed with a local signing secret. The URL defaults to `http://` when you omit the scheme, and only `http` and `https` URLs are accepted. Each event line then ends with the status code and response time of your endpoint, or with the error.

- The request times out after 10 seconds, and redirects are not followed.
- A failed delivery is shown and is not retried.
- The events keep arriving in the terminal whatever your endpoint answers.

The exact body, headers, and signature scheme are documented in [Event streams](https://cademi.dev/api/event-streams.md#local-development-with-the-cli). Verify the signature as described in [Webhooks](https://cademi.dev/api/webhooks.md#verifying-the-signature): the same code works with the local secret during development and with the webhook secret in production.

### The local signing secret

```sh
cademi listen --print-secret
```

The CLI creates a signing secret (`whsec_local_...`) the first time you run `cademi listen` with a profile, keeps it in the system keychain, and reuses it on every run, so you configure your receiver once. `--print-secret` prints it and exits. `cademi auth logout` deletes it with the profile's other secrets.

`CADEMI_LISTEN_SECRET` overrides the secret. When you use `CADEMI_API_KEY`, which bypasses profiles, the CLI generates a new secret on every run and warns you: set `CADEMI_LISTEN_SECRET` to keep it stable.

```sh
export CADEMI_LISTEN_SECRET=whsec_local_...
```

## Print events as JSON

```sh
cademi listen --json | jq -c 'select(.type == "user.created")'
```

With `--json`, each event prints as one line of JSON, the same object that `GET /events/{event_id}` returns. Status messages and forwarding results go to standard error, so you can pipe standard output to another program.

## Use an existing event stream

By default, each `cademi listen` creates its own event stream. To read an event stream you created with `cademi event-streams create`, pass its ID:

```sh
cademi event-streams create -f 'filters.event_types[]=user.created' -F expires_in_hours=24
cademi listen --stream str_01J8Z3...
cademi listen --stream str_01J8Z3... --last-event-id evt_01J8Z2...
```

The connection resumes from the cursor stored on the event stream. `--last-event-id` resumes after a specific event instead. The event stream keeps the filters and starting point it was created with: `--events`, `--resources`, and `--replay` apply only when the CLI creates the event stream. The CLI does not revoke an event stream passed with `--stream`.

An event stream accepts one connection at a time. If another `cademi listen` or another client is connected, the command fails with `stream_busy`. A connection left open by a client that stopped without closing it is released after 25 minutes.

`--keep` leaves the temporary event stream active when you stop the command, so you can reconnect to it later with `--stream` and the ID the CLI printed at startup.

## Connection and limits

- The CLI reconnects on its own when the server closes the connection or the network drops, and resumes after the last event it received, without repeating events. In human mode, it also renews the access token when needed.
- The command stops when the event stream expires or is revoked, when the credentials are revoked, or when the resume point is older than the retention period (`cursor_expired`). In that last case, recover older events with `cademi events list`.
- Each credential can have up to 5 active event streams, and each account up to 20. Beyond that, `cademi listen` fails with `429 too_many_streams`. List your event streams with `cademi event-streams list` and revoke unused ones with `cademi event-streams delete <event_stream_id>`.

## Produce events in the sandbox

In a sandbox, run a test scenario in a second terminal to produce events:

```sh
# terminal 1
cademi listen --forward-to localhost:3000/webhooks/cademi

# terminal 2
cademi sandbox test-scenarios list
cademi sandbox run scn_01J8Z3...
```

See [Sandbox](https://cademi.dev/cli/sandbox.md).

## Flags

| Flag | Effect |
|---|---|
| `--events <types>` | Only these event types. |
| `--resources <types>` | Only events about these resource types. |
| `--forward-to <url>` | `POST` each event to this URL, signed like a webhook delivery. |
| `--print-secret` | Print the local signing secret and exit. |
| `--json` | Print each event as one line of JSON. |
| `--replay` | Also deliver the retained events from before the command started. |
| `--stream <event_stream_id>` | Read an existing event stream instead of creating one. |
| `--last-event-id <event_id>` | Resume after this event. |
| `--keep` | Do not revoke the temporary event stream on exit. |
