# Event Monitoring Interface Stripe provides functions for monitoring payment intent status changes. Watchers receive callbacks whenever a payment intent transitions to a new state, enabling your application to react to successful payments, cancellations, and other status updates. ## `IntentChangeContext` The context object passed to every watcher callback. It carries metadata about the origin of the event. ```typescript interface IntentChangeContext { local: boolean; } ``` | Property | Type | Description | | -------- | --------- | ----------------------------------------------------------------------------------------------- | | `local` | `boolean` | `true` when the event was triggered by the current instance. `false` when it came from another cluster node. | This distinction is useful in clustered deployments where multiple instances receive the same Stripe webhook. By filtering on `context.local`, you can ensure that side effects such as sending emails or updating a database execute only once. ## `IntentWatcher` Callback Type All watcher functions accept a callback that conforms to the following signature: ```typescript type IntentWatcher = ( id: string | undefined, intent: Stripe.PaymentIntent, context: IntentChangeContext, ) => void; ``` | Parameter | Type | Description | | --------- | ---------------------- | ------------------------------------------------------------------ | | `id` | `string \| undefined` | The custom payload ID from `metadata.payload`, set during `InitializePayment`. | | `intent` | `Stripe.PaymentIntent` | The full payment intent object with its current state. | | `context` | `IntentChangeContext` | Event origin metadata. | ## `WatchAllPayments` Registers a callback that fires whenever any payment intent changes status. Use this for global side effects such as logging, analytics, or audit trails. ```typescript import { WatchAllPayments } from "@antelopejs/interface-stripe"; WatchAllPayments((id, intent, context) => { console.log(`Payment ${id} changed to status: ${intent.status}`); console.log(`Origin: ${context.local ? "local" : "remote"}`); if (intent.status === "succeeded") { // Handle successful payment } else if (intent.status === "canceled") { // Handle canceled payment } }); ``` ### Parameters | Parameter | Type | Required | Description | | ----------- | --------------- | -------- | -------------------------------------------------------------------- | | `callback` | `IntentWatcher` | Yes | Function invoked on every payment intent change. | | `onlyLocal` | `boolean` | No | When `true`, the callback fires only for events originating locally. Defaults to `false`. | ### Filtering Local Events In a clustered deployment, set `onlyLocal` to `true` to prevent duplicate processing across instances. ```typescript import { WatchAllPayments } from "@antelopejs/interface-stripe"; // Only react to events from the current instance WatchAllPayments((id, intent, context) => { if (intent.status === "succeeded") { sendConfirmationEmail(id); } }, true); ``` > **Tip:** The `onlyLocal` filter applies before the callback is invoked. When set to `true`, events from remote cluster nodes never reach the callback. ## `WatchPayment` Registers a callback for a specific payment intent. The callback fires whenever that payment intent changes status. Once the intent reaches a terminal state (`succeeded` or `canceled`), the watcher is automatically removed. ```typescript import { WatchPayment } from "@antelopejs/interface-stripe"; WatchPayment("pi_1234567890", (id, intent, context) => { if (intent.status === "succeeded") { console.log(`Payment ${id} completed successfully`); updateOrderStatus(id, "paid"); } else if (intent.status === "canceled") { console.log(`Payment ${id} was canceled: ${intent.cancellation_reason}`); updateOrderStatus(id, "canceled"); } else { console.log(`Payment ${id} status: ${intent.status}`); } }); ``` ### Parameters | Parameter | Type | Required | Description | | ------------------ | --------------- | -------- | ---------------------------------------------- | | `paymentIntentId` | `string` | Yes | The Stripe payment intent ID to monitor. | | `callback` | `IntentWatcher` | Yes | Function invoked when the intent changes state. | > **Note:** Unlike `WatchAllPayments`, the `WatchPayment` callback does not support the `onlyLocal` filter. It fires for both local and remote events. ## Automatic Cleanup When a payment intent reaches a terminal state (`succeeded` or `canceled`), the event system performs automatic cleanup: - Per-intent watchers registered with `WatchPayment` are removed. - Pending promises from `WaitForPayment` are resolved or rejected. This prevents memory leaks from watchers that are no longer needed. ## Combine Watchers with Payment Processing The following example creates a payment intent, watches for its completion, and returns the client secret for frontend confirmation. ```typescript import { InitializePayment, WatchPayment, WaitForPayment } from "@antelopejs/interface-stripe"; async function processAndMonitorPayment(orderId: string, amount: number) { const intent = await InitializePayment(orderId, { amount, currency: "usd", payment_method_types: ["card"], }); // Option A: React to status changes with a callback WatchPayment(intent.id, (id, updatedIntent, context) => { if (updatedIntent.status === "succeeded") { console.log(`Order ${id} has been paid`); } else if (updatedIntent.status === "canceled") { console.log(`Payment for order ${id} was canceled`); } }); // Option B: Await the terminal state with a promise try { const completed = await WaitForPayment(intent.id); console.log(`Order ${orderId} payment confirmed`); } catch (reason) { console.error(`Order ${orderId} payment failed:`, reason); } return intent; } ``` > **Important:** You can use `WatchPayment` and `WaitForPayment` on the same payment intent. Both mechanisms operate independently and are cleaned up automatically when the intent reaches a terminal state.