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

# Event envelope

> The structure every webhook delivery shares.

Every webhook Ionic sends has the same outer JSON shape — the *envelope*. The fields below are stable across all event types; the event-specific data lives under `data.object`.

```json theme={null}
{
  "id": "evt_2pXqL9mZ4kRb7VnT0sWcEfGh",
  "type": "payment_intent.succeeded",
  "created": "2026-05-01T18:24:05Z",
  "livemode": true,
  "api_version": "2026-05-01",
  "operations": ["refund"],
  "data": {
    "object": {
      "id": "pi_2pXqL9mZ4kRb7VnT0sWc",
      "object": "payment_intent",
      "status": "succeeded",
      "amount": 5000,
      "currency": "USD",
      "capture_method": "automatic",
      "latest_charge_id": "ch_2pXqL9mZ4kRb7VnT",
      "payment_method": "pm_2pXqL9mZ4kRb7VnT",
      "customer": null,
      "metadata": {},
      "livemode": true,
      "created_at": 1746122645,
      "updated_at": 1746122645
    }
  }
}
```

<Note>Abbreviated for clarity. See the [event catalog](/webhooks/events) for a complete example payload for every event type.</Note>

## Fields

| Field         | Type      | Description                                                                                                                           |
| ------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | string    | Unique event id, prefixed `evt_`. Stable across redeliveries — use it as your [deduplication key](/webhooks/idempotency-and-retries). |
| `type`        | string    | The event type in `resource.action` dot notation, e.g. `payment_intent.succeeded`. See the [catalog](/webhooks/events).               |
| `created`     | string    | RFC 3339 timestamp of when the event was created — **not** when it was delivered.                                                     |
| `livemode`    | boolean   | `true` for events from live keys, `false` for test mode.                                                                              |
| `api_version` | string    | The snapshot schema version, pinned per endpoint at creation (e.g. `2026-05-01`). `data.object` is shaped to this version.            |
| `operations`  | string\[] | Next-action verbs available on the resource for this event (e.g. `["refund"]`). Always an array — `[]` when there are none.           |
| `data.object` | object    | The full resource snapshot at the moment the event fired.                                                                             |

## `data.object` is the resource snapshot

`data.object` is the same shape the API returns from `GET /v1/<resource>/{id}` for that resource — a checkout session, payment intent, refund, invoice, subscription, credit note, or customer. Whatever fields you'd read from the API, you read here, with one difference: **buyer-frontend secrets are stripped** (for example `client_secret`), because the webhook is delivered server-to-server and those values are only meant for the browser.

This means you usually don't need a follow-up API call — the snapshot carries everything. When you do need the *current* state (because [ordering isn't guaranteed](/webhooks/idempotency-and-retries)), fetch the resource by its `id`.

<Note>
  The snapshot is taken **when the event is created**. If the resource changed
  afterward, `data.object` contains the earlier state. Retrieve the resource by
  `id` when you need its latest status.
</Note>

## `operations`

`operations` lists the actions that make sense on the resource in its current state — the same verbs the API exposes. For `payment_intent.succeeded` it's `["refund"]`; for `payment_intent.payment_failed` it's `["retry_with_new_payment_method"]`; for terminal events it's `[]`. Treat it as a hint for your UI or automation, not as an exhaustive permission list.

## `api_version`

Each endpoint pins an `api_version` when you create it. Every event delivered to that endpoint renders `data.object` in that version, so a schema change to a resource won't silently alter the payloads your handler already parses. To adopt a newer version, create a new endpoint (or update the existing one) with the version you want.
