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

# Webhooks

> Card webhook events and how to consume them

Cards add two webhook event types on top of Grid's existing webhook
infrastructure. Signature verification (`X-Grid-Signature`) and
retry behavior are identical to the rest of Grid — see
[Authentication](/api-reference/authentication) and
[Webhooks](/api-reference/webhooks) for the underlying mechanics.

Card-transaction lifecycle events are not card-specific webhooks —
they ride on the generic transaction webhook stream (a follow-up
extends the Transaction model with a card destination type).

## Event types

| Type                         | Fires on                                                                                                                  |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `CARD.STATE_CHANGE`          | `PENDING_ISSUE → ACTIVE`, `→ CLOSED (ISSUER_REJECTED)`, and every subsequent `ACTIVE ⇄ FROZEN` and `→ CLOSED` transition. |
| `CARD.FUNDING_SOURCE_CHANGE` | Whenever `PATCH /cards/{id}` updates the `fundingSources` array.                                                          |

All three carry the standard envelope:

```json theme={null}
{
  "id": "Webhook:019542f5-b3e7-1d02-0000-000000000020",
  "type": "CARD.STATE_CHANGE",
  "timestamp": "2026-05-08T14:11:00Z",
  "data": { /* the affected Card or CardTransaction resource */ }
}
```

The `id` is unique per delivery and safe to use for idempotency.

## CARD.STATE\_CHANGE

The `data` payload is the post-change `Card` resource. Example —
activation after issuance:

```json theme={null}
{
  "id": "Webhook:019542f5-b3e7-1d02-0000-000000000020",
  "type": "CARD.STATE_CHANGE",
  "timestamp": "2026-05-08T14:11:00Z",
  "data": {
    "id": "Card:019542f5-b3e7-1d02-0000-000000000010",
    "cardholderId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
    "state": "ACTIVE",
    "brand": "VISA",
    "form": "VIRTUAL",
    "last4": "4242",
    "expMonth": 12,
    "expYear": 2029,
    "panEmbedUrl": "https://embed.lithic.com/iframe/...?t=...",
    "fundingSources": [
      "InternalAccount:019542f5-b3e7-1d02-0000-000000000002"
    ],
    "currency": "USD",
    "createdAt": "2026-05-08T14:10:00Z",
    "updatedAt": "2026-05-08T14:11:00Z"
  }
}
```

Common branches to handle in your consumer:

* `state: "ACTIVE"` after `PENDING_ISSUE` — the card is live; surface
  `panEmbedUrl` to the cardholder.
* `state: "CLOSED"`, `stateReason: "ISSUER_REJECTED"` — the issuer
  rejected provisioning; offer to issue a new card.
* `state: "FROZEN"` / `state: "ACTIVE"` — reflect the freeze toggle in
  your UI.
* `state: "CLOSED"`, `stateReason: "CLOSED_BY_PLATFORM"` — close
  confirmed; stop showing the card.

## CARD.FUNDING\_SOURCE\_CHANGE

Fires whenever a `PATCH /cards/{id}` call changes the `fundingSources`
array. The `data` payload is the full `Card` resource with the
post-change `fundingSources`, so a consumer that only cares about the
current set of bindings can replace state wholesale.

## Card-transaction lifecycle

Authorization, pull, clearing, refund, and `EXCEPTION` transitions are
not delivered through a dedicated card webhook. They flow through
the generic transaction webhook stream that already carries
outgoing-payment lifecycle events; a follow-up PR adds the card
destination type to that stream. See
[Reconciliation](/cards/transactions/reconciliation) for the
underlying event model.

## Idempotency & retries

Webhook deliveries are at-least-once. Track processed `id` values and
return `200` on duplicates, or return `409` and let Grid stop
retrying. Both shapes are accepted by Grid's webhook infrastructure.
