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

# Events

> Consume tenant-scoped CloudEvents by pull or live stream, and inspect the retained stream's current position.

The Occtoo Events API lets you react to changes across your tenant — sources, cards, segments, destinations, endpoints, and users — without polling each resource. Every change is published as a [CloudEvents](https://cloudevents.io/) message (`application/cloudevents+json`).

## Consume and inspect events

<Columns cols={2}>
  <Card title="Pull">
    Page through events with `GET /v1/events` using a cursor. Good for batch processing and catch-up jobs.
  </Card>

  <Card title="Metadata">
    Inspect the first and latest retained positions and exact event count with `GET /v1/events/metadata`. Good for consumer health checks.
  </Card>

  <Card title="Stream" href="/api-reference/events/streaming">
    Subscribe to a live, ordered Server-Sent Events stream at `GET /v1/events/stream`. Good for real-time reactions.
  </Card>

  <Card title="Durable consumer" href="/api-reference/events/durable-consumers">
    Pull leased batches from a server-tracked position and acknowledge them. Good for competing workers that should not store their own cursor.
  </Card>
</Columns>

<Note>
  Occtoo can also push these events to you. Create a webhook, Azure Storage Queue or Azure Service Bus subscription in Studio — see [Find event subscriptions](/guides/studio/events/find-subscriptions).
</Note>

## Filter by subject

Use the `filter` query parameter to select events about one entry or resource. The same expression works with pull (`GET /v1/events`), metadata (`GET /v1/events/metadata`), and SSE (`GET /v1/events/stream`).

```bash theme={null}
curl --get 'https://api.occtoo.com/v1/events' \
  --header 'Authorization: Bearer <access-token>' \
  --data-urlencode 'filter=type eq "source_entry.updated" and sourceId eq "products" and subject eq "sku-123"'
```

`subject` is a CloudEvent envelope field. Compare its complete value as an exact, case-sensitive string. Do not split it on `/` or `.`: those characters can be part of an ID. Partial and wildcard matches are not supported.

Its meaning depends on the event type:

| Event family | `subject` identifies |
| - | - |
| `source.*` | The source (`sourceId`). |
| `source_entry.*` | The entry within its source (`entryKey`). |
| `card_definition.*` | The card definition (`cardDefinitionId`). |
| `card.*` | The card (`cardId`). |
| `segment.*` | The segment (`segmentId`). |
| `destination.*` | The destination, or its API-version ID when a destination ID was not supplied. |
| `destination_entry.*` | The destination entry (`entryId`). |
| `endpoint.*` | The endpoint (`endpointId`). |
| `user.*` | The user (`userId`). |

Combine `subject` with the event type and parent identifiers to distinguish entries that share an ID:

```text Card theme={null}
type eq "card.updated" and cardDefinitionId eq "products" and subject eq "card-123"
```

```text Destination entry theme={null}
type eq "destination_entry.updated" and destinationId eq "catalog" and apiVersion eq "3" and endpointId eq "products" and subject eq "entry-123"
```

The field names `entryKey`, `cardId`, and `entryId` are not separate filter operands. Use `subject` for these values. Check `GET /v1/event-types` for the properties supported by each type.

<Note>
  Only events processed after subject filtering was enabled can match a subject condition. Older retained events are not backfilled, even when their payload contains `subject`. Filters without a subject condition continue to match older events. An `or` branch without a subject condition can also match them.
</Note>

You can combine comparisons with `and`, `or`, and parentheses. Filter values must be double-quoted strings of 1–200 characters. The existing limits remain 4,096 characters per expression, 50 comparisons, and eight nesting levels.

The same subject matching applies to webhook and queue subscription filters. Every branch of a subscription filter must also constrain `type`.

## Inspect stream metadata

Call `GET /v1/events/metadata` to inspect the retained stream without retrieving event payloads. It accepts the same optional `filter` as the pull and stream endpoints.

```bash theme={null}
curl --get 'https://api.occtoo.com/v1/events/metadata' \
  --header 'Authorization: Bearer <access-token>' \
  --data-urlencode 'filter=type eq "source.updated" and sourceId eq "products"'
```

```json theme={null}
{
  "first": {
    "sequence": "003.00000000000000184001",
    "time": "2026-07-04T08:10:00Z"
  },
  "latest": {
    "sequence": "003.00000000000000184467",
    "time": "2026-07-04T09:15:12.345Z"
  },
  "after": "<opaque pull cursor>",
  "total": 184
}
```

* `first` and `latest` identify the boundaries of the retained filtered view. Their `time` is `null` when the CloudEvent has no time.
* `after` is an opaque pull cursor for the `latest` position. Store it as a checkpoint or pass it to `GET /v1/events`.
* `total` is the exact count across the complete retained filtered view, not the count after a consumer checkpoint.

Compare `latest.sequence` with your last successfully processed sequence to determine whether a consumer is caught up. Do not use the difference between sequences as a pending-event count because filtered-out events can create gaps.

When no retained event matches, `first`, `latest`, and `after` are `null`, and `total` is `0`.

## Event types

Occtoo publishes 30 event types across sources, cards, segments, destinations, endpoints and users. All are currently at payload schema version `1.0`.

Every `data` payload includes these two properties, so they are omitted from the tables below:

| Property | Type | Description |
| - | - | - |
| `correlationIds` | `string[]` | Ids correlating this event with the operation that caused it. Always present. |
| `actor` | `object \| null` | Who caused the change, as `{ "id": "<user or service id>" }`. `null` for system-initiated changes. |

In the tables, `?` marks a property that is not required — it may be absent or `null`. See the [data property reference](#data-property-reference) for types and meanings.

### Sources

| Event type | Description | Data properties |
| - | - | - |
| `source.created` | A source was created. | `sourceId` |
| `source.updated` | A source configuration changed. | `sourceId`, `changes`, `properties?` |
| `source.deleted` | A source was deleted. | `sourceId` |
| `source_entry.added` | A source entry was added. | `sourceId`, `entryKey`, `version`, `properties?` |
| `source_entry.updated` | A source entry changed. | `sourceId`, `entryKey`, `version`, `changedProperties`, `valuesTruncated`, `values?` |
| `source_entry.deleted` | A source entry was deleted. | `sourceId`, `entryKey`, `version` |

### Cards

| Event type | Description | Data properties |
| - | - | - |
| `card.updated` | A card changed as a result of source data. | `cardDefinitionId`, `cardId`, `changedProperties` |
| `card.segment_membership_changed` | A card entered or left a segment. | `cardDefinitionId`, `cardId`, `segmentId`, `change` |
| `card_definition.created` | A card definition was created. | `cardDefinitionId` |
| `card_definition.updated` | A card definition changed. | `cardDefinitionId`, `changes` |
| `card_definition.activated` | A card definition became active. | `cardDefinitionId` |
| `card_definition.deleted` | A card definition was deleted. | `cardDefinitionId` |
| `card_definition.restored` | A card definition was restored. | `cardDefinitionId` |

### Segments

| Event type | Description | Data properties |
| - | - | - |
| `segment.created` | A segment was created. | `segmentId`, `segmentDefinitionId`, `cardDefinitionId?` |
| `segment.updated` | A segment changed. | `segmentId`, `segmentDefinitionId`, `changes`, `cardDefinitionId?` |
| `segment.archived` | A segment was archived. | `segmentId`, `segmentDefinitionId`, `cardDefinitionId?` |
| `segment.restored` | A segment was restored. | `segmentId`, `segmentDefinitionId`, `cardDefinitionId?` |
| `segment.deleted` | A segment was deleted. | `segmentId`, `segmentDefinitionId`, `cardDefinitionId?` |

### Destinations

| Event type | Description | Data properties |
| - | - | - |
| `destination.created` | A destination was created. | `destinationId` |
| `destination.published` | A destination was published. | `destinationId` |
| `destination.stopped` | A destination was stopped. | `destinationId` |
| `destination.deleted` | A destination was deleted. | `destinationId` |
| `destination_entry.updated` | An entry was written to a destination endpoint. | `destinationId`, `apiVersionId`, `apiVersion`, `endpointId`, `endpoint`, `entryId`, `version`, `changedProperties`, `valuesTruncated`, `values?` |
| `destination_entry.deleted` | An entry was removed from a destination endpoint. | `destinationId`, `apiVersionId`, `apiVersion`, `endpointId`, `endpoint`, `entryId`, `version` |

### Endpoints

| Event type | Description | Data properties |
| - | - | - |
| `endpoint.created` | A destination endpoint was created. | `destinationId`, `apiVersionId`, `apiVersion`, `endpointId` |
| `endpoint.updated` | A destination endpoint changed. | `destinationId`, `apiVersionId`, `apiVersion`, `endpointId` |
| `endpoint.deleted` | A destination endpoint was deleted. | `destinationId`, `apiVersionId`, `apiVersion`, `endpointId` |

### Users

| Event type | Description | Data properties |
| - | - | - |
| `user.created` | A tenant user was created. | `userId`, `email?`, `firstName?`, `lastName?` |
| `user.updated` | A tenant user changed. | `userId`, `email?`, `firstName?`, `lastName?` |
| `user.deleted` | A tenant user was deleted. | `userId`, `email?`, `firstName?`, `lastName?` |

## Data property reference

Properties marked **filterable** can be used in the filter grammar of `GET /v1/events`, `GET /v1/events/metadata`, and `GET /v1/events/stream`. The exact set accepted for a given type is returned as `filterableProperties` by `GET /v1/event-types`. You can also filter by the envelope fields `type` and [`subject`](#filter-by-subject).

| Property | Type | Filterable | Description |
| - | - | - | - |
| `apiVersion` | `string` | Yes | Destination API version name the endpoint belongs to. |
| `apiVersionId` | `string` | Yes | Identifier of the destination API version. |
| `cardDefinitionId` | `string` | Yes | Identifier of the card definition. Nullable on `segment.*` events. |
| `cardId` | `string` | — | Identifier of the individual card. |
| `change` | `string` | — | The membership change that occurred on `card.segment_membership_changed`. |
| `changedProperties` | `string[]` | — | Names of the properties that changed. |
| `changes` | `string[]` | — | Names of the configuration areas that changed. |
| `destinationId` | `string` | Yes | Identifier of the destination. |
| `email` | `string \| null` | — | User email address. |
| `endpoint` | `string` | — | Name of the destination endpoint. |
| `endpointId` | `string` | Yes | Identifier of the destination endpoint. |
| `entryId` | `string` | — | Identifier of the destination entry. |
| `entryKey` | `string` | — | Key of the source entry within its source. |
| `firstName` | `string \| null` | — | User first name. |
| `lastName` | `string \| null` | — | User last name. |
| `properties` | `array \| null` | — | On `source.updated`, the changed source properties as `{ "id", "change" }` objects. On `source_entry.added`, the entry's properties. |
| `segmentDefinitionId` | `string` | Yes | Identifier of the segment definition. |
| `segmentId` | `string` | Yes | Identifier of the segment. |
| `sourceId` | `string` | Yes | Identifier of the source. |
| `userId` | `string` | Yes | Identifier of the tenant user. |
| `values` | `object \| null` | — | Changed values keyed by property name, each an array of `{ "value", "language?" }`. Omitted when `valuesTruncated` is `true`. |
| `valuesTruncated` | `boolean` | — | Whether `values` was dropped because the payload exceeded the size limit. |
| `version` | `string \| integer` | — | Monotonic version of the entry, as an integer-valued string or integer. |

<Note>
  `GET /v1/event-types` is the authoritative, machine-readable version of this page — it returns each type's description, `filterableProperties` and full inline JSON Schema. Fetch a single schema with `GET /v1/events/schemas/{type}/{version}`.
</Note>

## Resuming a stream

The SSE `id` field of each streamed event contains a raw, resumable event sequence. Pass it (or a pull cursor) as the `after` query parameter when reconnecting to continue exactly where you left off — no events lost, none replayed.

<Note>
  The Events API uses the same authentication as the rest of the platform API: a bearer token or API key. See the [API overview](/api-reference/overview#authentication) for how to obtain tokens.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.