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

# List Events

> Read your organization's event ledger, with a replay checkpoint

<Info>
  **Beta.** The event ledger and its replay rail are stable enough to build on,
  but the per-event `data` payloads are versioned by `payload_version` and their
  shape is not yet frozen. Pin `payload_version` in your consumer and read the
  [changelog](/changelog) before upgrading.
</Info>

## Overview

Every webhook Signa sends you is also a row in your organization's event ledger, addressable by the same `evt_*` id that arrives in the `webhook-id` header. The ledger is append-only and retained for **30 days**.

Two ways to read it:

* **Newest first** (`sort=-id`, the default) with `cursor` — a browse/tail feed.
* **Oldest first** (`sort=id`) with `after` — a durable replay from a checkpoint you persist. This is the recovery path when your receiver was down: store the last `evt_*` you processed, and ask for everything after it.

Requires the `events:read` scope.

## Query Parameters

<ParamField query="limit" type="integer" default="20">Page size (1-100).</ParamField>
<ParamField query="cursor" type="string">Opaque cursor from the previous response. Cannot be combined with `after`.</ParamField>
<ParamField query="sort" type="string" default="-id">`-id` (newest first) or `id` (oldest first). `after` requires `id`.</ParamField>
<ParamField query="after" type="string">Exclusive `evt_*` replay checkpoint. Valid only with `sort=id`. Returns `410 replay_window_expired` when the checkpoint has aged out of the 30-day window.</ParamField>
<ParamField query="event_type" type="string">Filter by event type(s), comma-separated: `alert.created`, `trademark.status_changed`, `office_action.issued`.</ParamField>
<ParamField query="office_code" type="string">Filter by office code(s), comma-separated. WIPO ST.3 uppercase (`US`, `EM`); legacy acronym slugs (`uspto`, `euipo`) and `EU` are also accepted.</ParamField>
<ParamField query="trademark_id" type="string">Filter by trademark ID (`tm_*`).</ParamField>
<ParamField query="since" type="string">ISO date or timestamp — events recorded by Signa at or after this time.</ParamField>
<ParamField query="portfolio_id" type="string">Filter by the portfolio membership snapshot taken when the event was recorded. Applies to **every** family, `alert.created` included: an alert is in the portfolio only when its matched mark was a member at event time. Later membership changes never rewrite history. Requires `portfolios:manage`.</ParamField>

## Response

<ResponseField name="object" type="string">Always `"list"`.</ResponseField>

<ResponseField name="data" type="object[]">
  Array of event summaries.

  <Expandable title="event">
    <ResponseField name="id" type="string">Event ID (`evt_*`, opaque). The same value arrives in the `webhook-id` header of the matching delivery.</ResponseField>
    <ResponseField name="object" type="string">Always `"event"`.</ResponseField>
    <ResponseField name="type" type="string">Event slug, e.g. `trademark.status_changed`.</ResponseField>
    <ResponseField name="trademark_id" type="string | null">The mark this event is about (`tm_*`), or `null` for families with no trademark identity.</ResponseField>
    <ResponseField name="office_code" type="string | null">WIPO ST.3 office code, or `null`.</ResponseField>
    <ResponseField name="occurred_at" type="string">When **Signa** produced the event: ingestion time for `trademark.*` and `office_action.*`, alert-creation time for `alert.created`. Not the office's own date — that is `source_date` on the detail body.</ResponseField>
    <ResponseField name="recorded_at" type="string">When the ledger row was written.</ResponseField>
    <ResponseField name="created_at" type="string">Alias of `recorded_at`.</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="has_more" type="boolean">Whether another page exists.</ResponseField>
<ResponseField name="pagination" type="object">`{ cursor }` — opaque next-page cursor, `null` when exhausted.</ResponseField>

## Errors

| Status | `type`                              | When                                                                                                         |
| ------ | ----------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| 400    | `validation_error`                  | Bad query parameter — `after` blank, `after` with `cursor`, `after` without `sort=id`, unknown `office_code` |
| 400    | `cursor_expired` / `cursor_invalid` | Malformed/tampered cursor, or one reused with different bound parameters                                     |
| 403    | `forbidden`                         | Missing `events:read` (or `portfolios:manage` when using `portfolio_id`)                                     |
| 404    | `not_found`                         | `portfolio_id` doesn't exist or belongs to another org                                                       |
| 410    | `replay_window_expired`             | The `after` checkpoint is older than the 30-day retention window                                             |

## Code Examples

<CodeGroup>
  ```bash cURL theme={null}
  # Tail the feed
  curl "https://api.signa.so/v1/events?limit=20" \
    -H "Authorization: Bearer sig_YOUR_KEY"

  # Replay from a stored checkpoint
  curl "https://api.signa.so/v1/events?sort=id&after=evt_3D7rZ9&limit=100" \
    -H "Authorization: Bearer sig_YOUR_KEY"
  ```

  ```ts TypeScript theme={null}
  // Replay everything you missed, oldest first.
  const page = await signa.events.list({ sort: 'id', after: lastProcessedId, limit: 100 });
  for await (const event of page) {
    await handle(event);
  }
  ```
</CodeGroup>

<ResponseExample>
  ```json 200 theme={null}
  {
    "object": "list",
    "data": [
      {
        "id": "evt_3D7rZ9",
        "object": "event",
        "type": "trademark.status_changed",
        "trademark_id": "tm_9vXq3Rmt",
        "office_code": "US",
        "occurred_at": "2026-08-14T09:10:00.000Z",
        "recorded_at": "2026-08-14T09:10:02.000Z",
        "created_at": "2026-08-14T09:10:02.000Z"
      }
    ],
    "has_more": false,
    "pagination": { "cursor": null },
    "request_id": "req_3vXq7RmT"
  }
  ```
</ResponseExample>

## Related Endpoints

* [Retrieve Event](/api-reference/monitoring/events/retrieve) - full detail with field-level before/after diffs
* [List Alerts](/api-reference/monitoring/alerts/list) - the alert resource an `alert.created` event wraps
* [Webhooks](/guides/monitoring/webhooks) - the push rail carrying the same `evt_*` ids
