[data-reveal]{opacity:1!important;transform:none!important}
Event Monitoring
Stripe

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.

Use WatchPayment for one intent and WatchAllPayments for cross-payment observers. Callbacks run in memory, not in a durable job queue. The sendConfirmationEmail and updateOrderStatus calls below are application placeholders; supply your own idempotent handlers and handle their errors.

Observe a payment

Register a watcher for an intent ID saved by your checkout code. This logs future events supplied by the configured implementation; it does not retrieve the current Stripe status or replay events that arrived before registration.

import { WatchPayment } from "@antelopejs/interface-stripe";

WatchPayment("pi_replace_with_your_test_intent", (orderId, intent) => {
  console.log({ orderId, paymentIntentId: intent.id, status: intent.status });
});

Use WaitForPayment when you need to retrieve the current status before waiting for a terminal event. Persist the intent ID so your application can reconcile after a restart.

Keep callbacks short and handle errors inside them. The dispatcher calls them synchronously and does not await returned promises. A synchronous throw can interrupt later callbacks and terminal cleanup; asynchronous work needs its own rejection handling and recovery policy.

IntentChangeContext

The context object passed to every watcher callback. It carries metadata about the origin of the event.

interface IntentChangeContext {
  local: boolean;
}
PropertyTypeDescription
localbooleantrue 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 an instance forwards events to other instances. Filtering on context.local skips those forwarded events, but does not deduplicate repeated webhook deliveries. Make side effects such as sending emails or updating a database idempotent.

IntentWatcher Callback Type

All watcher functions accept a callback that conforms to the following signature:

type IntentWatcher = (
  id: string | undefined,
  intent: Stripe.PaymentIntent,
  context: IntentChangeContext,
) => void;
ParameterTypeDescription
idstring | undefinedThe custom payload ID from metadata.payload, set during InitializePayment.
intentStripe.PaymentIntentThe full payment intent object with its current state.
contextIntentChangeContextEvent 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.

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

ParameterTypeRequiredDescription
callbackIntentWatcherYesFunction invoked on every payment intent change.
onlyLocalbooleanNoWhen true, the callback fires only for events originating locally. Defaults to false.

Filtering Local Events

In a clustered deployment, set onlyLocal to true to skip events forwarded from other instances. This is not an exactly-once delivery guarantee.

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.

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

ParameterTypeRequiredDescription
paymentIntentIdstringYesThe Stripe payment intent ID to monitor.
callbackIntentWatcherYesFunction 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 cleanup applies to per-intent registrations after a terminal event is processed. Global watchers remain registered; neither watcher function returns an unsubscribe handle. Register global observers at application startup rather than once per request.

Combine Watchers with Payment Processing

The following example creates a payment intent, watches for its completion, and returns the client secret for frontend confirmation.

import { InitializePayment, WatchPayment } from "@antelopejs/interface-stripe";

async function processAndMonitorPayment(orderId: string, amount: number) {
  const intent = await InitializePayment(orderId, {
    amount,
    currency: "usd",
    payment_method_types: ["card"],
  });

  // Register without waiting, then let the browser confirm the payment.
  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`);
    }
  });

  return {
    clientSecret: intent.client_secret,
    paymentIntentId: intent.id,
  };
}

Watchers live in memory, so persist the intent ID and reconcile unfinished orders after a restart. See the separate reconciliation example.

Important: You can use WatchPayment and WaitForPayment on the same payment intent. Do not await completion before returning the client secret. Both mechanisms are cleaned up automatically when the intent reaches a terminal state.