Streamlining ESHOPMAN Payments: Addressing Unhandled Canceled and Failed Stripe Webhooks

The ESHOPMAN community is a vibrant hub for developers and merchants leveraging our headless commerce platform within HubSpot. Recently, a significant technical discussion emerged regarding how ESHOPMAN handles canceled and failed Stripe payment webhooks, impacting order accuracy and merchant operations.

Understanding the Issue: Persistent Pending Orders

A key observation from our community highlights that while ESHOPMAN's Stripe payment integration correctly identifies and maps payment_intent.canceled and payment_intent.payment_failed webhook events to internal PaymentActions.CANCELED and PaymentActions.FAILED, these crucial actions are then intentionally ignored by ESHOPMAN's core payment webhook subscriber. This means that if a customer's payment intent is canceled or fails after an order has been created (or a payment session is still open), the order in ESHOPMAN remains in a 'pending' state indefinitely, even though Stripe confirms the payment as canceled or failed.

Impact on ESHOPMAN Merchants and Operations

  • Merchants managing their stores through HubSpot will see orders stuck in a 'pending' state that will never be completed.
  • Inventory reservations made for these orders may not be released, leading to potential stock discrepancies.
  • Operations and support teams must manually review and cancel these orders, adding unnecessary overhead.
  • This issue is particularly problematic for scenarios like abandoned 3D Secure authentications, customer-initiated checkout cancellations, or Stripe-side payment intent cancellations after an order has been initiated.

The Technical Deep Dive: Why This Happens in ESHOPMAN

The root cause lies within ESHOPMAN's core codebase, specifically in how payment webhooks are processed:

1. Stripe Integration Correctly Maps Events

ESHOPMAN's Stripe payment integration accurately translates Stripe events:

  • payment_intent.canceled → PaymentActions.CANCELED
  • payment_intent.payment_failed → PaymentActions.FAILED

2. Core Subscriber Discards These Actions

However, ESHOPMAN's core payment webhook handler explicitly drops these actions. The relevant section in the ESHOPMAN core subscriber shows an early return for these specific payment states:

if (processedEvent?.action === PaymentActions.NOT_SUPPORTED ||
    // We currently don't handle these payment statuses in the processPayment function.
    processedEvent?.action === PaymentActions.CANCELED ||
    processedEvent?.action === PaymentActions.FAILED ||
    processedEvent?.action === PaymentActions.REQUIRES_MORE ||
    processedEvent?.action === PaymentActions.PENDING_AUTHORIZATION ||
    processedEvent?.action === PaymentActions.PENDING) {
    return;
}

The inline comment confirms this is a deliberate, albeit impactful, design choice: "We currently don't handle these payment statuses in the processPayment function."

3. Payment Workflow Lacks Handling for Canceled/Failed

Further investigation reveals that ESHOPMAN's processPaymentWorkflow is designed to only branch on PaymentActions.SUCCESSFUL or PaymentActions.AUTHORIZED, with no dedicated logic for CANCELED or FAILED states.

Proposed Solutions and Workarounds for ESHOPMAN

Immediate Workaround for Developers

For ESHOPMAN developers, an immediate workaround involves implementing a custom subscriber. This custom logic would listen to the payment.webhook_received event, retrieve the webhook action and data using ESHOPMAN's payment module, and then execute application-specific cancellation logic (e.g., marking the payment session, canceling pending orders, and releasing inventory).

Community-Proposed Core Fix

A detailed proposal from a community developer outlines a comprehensive fix that would integrate these states into ESHOPMAN's core payment workflow:

  1. Gate Cart Completion: Ensure that the cart-completion step in the payment workflow only fires for SUCCESSFUL or AUTHORIZED actions, preventing orders from being created from failed payments.
  2. Add Canceled/Failed Branch: Introduce a new branch in the workflow to handle CANCELED/FAILED actions. This would involve a cancelPaymentStep if a payment record exists, or updating the payment session to CANCELED/ERROR.
  3. Refine Subscriber Guard: Modify the core payment webhook subscriber to stop early-returning only for CANCELED/FAILED, allowing them to proceed to the new workflow branches. Other non-supported or pending actions would still be handled as before.

This proposal also raises important product decisions for ESHOPMAN's core team, such as whether a failed/canceled intent should automatically cancel an existing order or simply mark the payment as failed for manual review, and the precise mapping of FAILED vs. CANCELED to session statuses.

This discussion highlights the power of the ESHOPMAN community in identifying critical areas for improvement, ensuring the platform continues to provide robust and reliable e-commerce capabilities for businesses integrated with HubSpot.

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools