Systems & Automation

How I Route Stripe Payment Events Into the Support Queue With Zapier

By Felix Maru · October 20, 2026 · 7 min read

Payment failure tickets are the worst ones to handle blind. A customer emails saying their card was declined or their subscription stopped working, and the agent opens the ticket with no context at all: was it a one-time charge? A recurring subscription? What did Stripe actually return as the error code? Was this the first attempt or the third retry?

The agent spends the first few minutes clicking into Stripe manually, searching by email, hoping the customer used the same address on their Stripe record, finding the payment, reading the error. All of that before they have written a single useful sentence to the customer. At a busy billing queue that adds up fast, and it quietly erodes the quality of first replies.

The fix is straightforward: wire Stripe events into Zapier so the ticket arrives pre-loaded with context. Here is exactly how I build it.

What you are actually wiring up

The goal is simple. When a payment event in Stripe matters to a customer, your support tool should know about it before the customer has to tell you. That means three things need to happen automatically:

  1. Stripe fires a webhook event when something changes on a payment or subscription.
  2. Zapier catches it, formats the relevant context into readable text, and creates a ticket.
  3. The ticket lands in the right queue with enough information for the agent to act immediately, no tab-switching required.

The list of events worth wiring up is shorter than you might think. Stripe fires dozens of event types internally (retries, ledger entries, status transitions between its own states). You want the handful that directly change a customer's experience or require a human response within a meaningful timeframe.

Choosing the right Stripe triggers

In Zapier, you will use the "New Event" trigger for Stripe. The event type filter is where the real value lives. After building this setup for several different clients, these are the four events that consistently earn a ticket:

payment_intent.payment_failed is the one you absolutely want. Every failed charge attempt should surface to the billing queue. Stripe includes the decline code and a human-readable message in the event payload, so the agent knows whether it was a card issue, a fraud block, or insufficient funds before they type a word.

invoice.payment_failed is specifically for subscription billing. Stripe retries failed subscription invoices on a configurable schedule, but the first failure is the window where a quick outreach actually prevents churn. By the time the subscription cancels after exhausted retries, it is often too late.

customer.subscription.deleted covers cancellations, both voluntary (the customer cancelled from the portal) and involuntary (retries exhausted). You need to treat these very differently. I will come back to this.

charge.dispute.created fires when a chargeback opens. These have a response deadline, typically 7 to 10 business days, and missing it means automatic loss. A ticket should appear the same day, not when someone remembers to check the Stripe dashboard.

Skip payment_intent.succeeded, charge.succeeded, and the dozens of internal state events. Those are noise for a support queue. You do not need a ticket every time a payment processes correctly.

Building the Zapier flow

I set up a separate Zap for each event type rather than routing everything through one Zap with branch logic. It makes each flow easier to debug and easier to change when one event needs different handling than another.

The structure for payment_intent.payment_failed looks like this:

Step 1 (Trigger): Stripe, trigger event set to "New Event," event type filtered to payment_intent.payment_failed.

Step 2 (Filter): Only continue if data.object.amount is greater than 0. This keeps test-mode authorizations and free-tier edge cases out of the queue. Simple to add, easy to forget, and the first thing that causes phantom tickets when you skip it.

Step 3 (Formatter): Use Zapier's Formatter step to convert the amount from cents to a readable currency figure. Stripe stores everything in the smallest currency unit, so a $49.00 charge arrives as 4900. Divide by 100 here, before the ticket body is written.

Step 4 (Create ticket): I use Help Scout in this example, but the same pattern maps directly to Zendesk, Front, or any tool with a Zapier action.

The ticket body should include: customer email (from data.object.receipt_email), amount attempted, currency, failure reason (from data.object.last_payment_error.message), the decline code (from data.object.last_payment_error.decline_code), and a direct URL to the payment in the Stripe dashboard. That last one matters more than you might expect. Build it by prepending the literal string https://dashboard.stripe.com/payments/ to the payment intent ID. The agent clicks once and lands directly on the record, already authenticated.

Step 5 (Route): Tag the ticket "billing-failure" and assign it directly to a billing queue, not the general inbox. Agents handling billing issues should have Stripe access, or at minimum read access. Routing billing failures into the general queue means a frontline agent opens it, cannot act on it, and reassigns it. That extra round-trip delays the response and frustrates the agent.

Stripe event fires → Filter (live mode, amount > 0) → Format context → Create ticket with Stripe link → Agent reviews and acts
The full flow from Stripe event to billing queue. The agent's job starts with context already in hand, not a Stripe lookup.

Getting the ticket context right

The decline reason field from Stripe is useful but can be terse. insufficient_funds and card_declined are clear enough that an agent knows what to say. But some codes, like generic_decline or card_velocity_exceeded, are less obvious and benefit from a plain-English note in the ticket.

Add a Formatter "Lookup Table" step between the raw event and the ticket creation step. Map the common decline codes to friendlier internal labels: generic_decline becomes "Card declined by bank (no specific reason given), suggest customer retry with a different card or call their bank." It takes fifteen minutes to build once and saves time on every billing ticket going forward.

For the customer.subscription.deleted event, add logic to distinguish voluntary from involuntary cancellations. Stripe sends a cancellation_details.reason field on the subscription object when a customer cancels through the customer portal. If that field is present and populated, the cancellation was voluntary and it routes to account management. If it is absent or null, retries likely exhausted and it routes to billing recovery. These two situations need completely different conversations, and routing them to the same queue means agents start without knowing which one they are in.

Two things I got wrong the first time

The first mistake was routing customer.subscription.deleted to the same queue as payment_intent.payment_failed. I described this above, but it is worth flagging as a real operational problem. A billing queue handled a string of voluntary cancellations that should have gone to account management, and the responses were off-tone because the agents were in the wrong headspace. The fix was adding the cancellation_details.reason check, but I should have built it from day one.

The second mistake was forgetting to filter out Stripe test mode events. When developers run test payments against the Stripe test environment, those events trigger the Zap in exactly the same way as live events. The queue starts filling with test tickets, and agents start asking what is going on. The fix is a filter step at the top of every Zap: only continue if livemode equals true. It is one of the simplest filter conditions in Zapier and the one I now add before anything else.

Once both are in place, the setup runs quietly. Payment events surface to the right queue within a minute or two of firing in Stripe. Agents open billing tickets already knowing what happened. The customer writes in, and the first reply can acknowledge the specific issue rather than asking them to clarify what they already told you.

That is the part customers actually notice.


Sources: Stripe API: Event types · Stripe: Decline codes · Zapier Stripe integrations

Questions about this setup or running a different support tool? Get in touch.