← Back to all posts
4 min readCentrali Team

Get Alerted When a Stripe Charge Fails — No Cloud Vendor Required

Build a real-time alert for failed Stripe charges in under 5 minutes. One function, one trigger, any messaging tool — no AWS, no Azure, no polling.

TutorialIntegrationCompute

A charge fails. Nobody notices. The customer retries, gets frustrated, emails support. Support logs into Stripe, finds the charge.failed event, and starts debugging — hours or days after it happened.

Stripe can forward events to your endpoint, but it doesn't notify your team. You still need to build the alerting yourself. Stripe's Event Destinations can push to AWS EventBridge or Azure Event Grid, but that means an AWS or Azure account, IAM roles, an event bus, and a cloud bill — all for a notification.

This walkthrough builds a real-time alert that fires the moment a charge.failed event arrives. One function, one trigger, any messaging tool you want. No cloud vendor, no polling, no infrastructure.

Prerequisites: This builds on Store Stripe Webhook Events and Query Them Forever. If you've already got a stripe-events collection receiving events, you're ready. If not, that post takes about 5 minutes.

Step 1: Allowlist Your Messaging Domain

Centrali's compute sandbox restricts outbound HTTP to domains you've explicitly approved. Before your function can post alerts, add your messaging provider's domain.

Go to Logic > Domains and add the domain for your tool:

Allowed domains showing hooks.slack.com, discord.com, and webhook.office.com

Messaging ToolDomain to Add
Slackhooks.slack.com
Discorddiscord.com
Microsoft Teamswebhook.office.com
Email (via HTTP API)Your email provider's API domain
Custom endpointYour server's domain

Step 2: Write the Alert Function

Go to Logic > Functions and create a new function called Alert on Charge Failed.

Function editor with Alert on Charge Failed code

javascript
async function run() { const record = executionParams.data; const event = record.data; if (event.eventType !== 'charge.failed') return; const amount = (event.amount / 100).toFixed(2); const currency = (event.currency || 'usd').toUpperCase(); const message = [ 'Charge Failed', 'Amount: ' + currency + ' ' + amount, 'Customer: ' + (event.customerId || 'unknown'), 'Event: ' + event.eventId, 'Time: ' + new Date(event.created * 1000).toISOString(), ].join('\n'); api.log({ message: 'Sending alert', amount: currency + ' ' + amount, eventId: event.eventId }); await api.httpPost(triggerParams.alertUrl, { text: message }); api.log({ message: 'Alert sent', eventId: event.eventId }); }

A few things to note:

  • executionParams.data is the record that was created in your stripe-events collection. The record's data field contains the flattened event fields (eventType, amount, customerId, etc.) from the store function in Post 1.
  • triggerParams.alertUrl is an encrypted parameter you'll set on the trigger — your Slack webhook URL, Discord webhook, or any HTTP endpoint.
  • The function filters for charge.failed events only. Every other event type exits early without sending an alert.

Step 3: Create the Event-Driven Trigger

Go to Logic > Triggers and create a new trigger.

Trigger config showing event-driven setup for stripe-events

FieldValue
NameStripe Charge Failed Alert
FunctionAlert on Charge Failed
TypeEvent-Driven
Eventrecord_created
Collectionstripe-events

Under Trigger Parameters, add:

ParameterValue
alertUrlYour webhook URL (e.g., https://hooks.slack.com/services/T.../B.../xxx)

Trigger parameters are encrypted at rest. Your webhook URL is never exposed in logs or function code.

Step 4: Test It

Trigger a failed charge from the Stripe CLI:

bash
stripe trigger charge.failed

Or send a test webhook from the Stripe Dashboard. Within seconds, you should see the alert arrive:

Slack channel showing Charge Failed alerts with amount, customer, and event details

Open the run detail in the Centrali console to see the execution:

Run detail showing completed execution with Sending alert and Alert sent logs

Adapting for Other Messaging Tools

The function posts { text: message }, which works with Slack and most webhook APIs. For other tools, adjust the payload:

Discord:

javascript
await api.httpPost(triggerParams.alertUrl, { content: message });

Microsoft Teams:

javascript
await api.httpPost(triggerParams.alertUrl, { "@type": "MessageCard", text: message, });

Any HTTP endpoint:

javascript
await api.httpPost(triggerParams.alertUrl, { event: 'charge.failed', amount, currency, customerId: event.customerId, eventId: event.eventId, });

Going Further

This pattern isn't limited to failed charges. You can alert on any event type by adjusting the filter:

  • Disputes: Change the check to event.eventType !== 'charge.dispute.created'
  • Failed invoices: event.eventType !== 'invoice.payment_failed'
  • All failures: Remove the filter entirely and alert on every event
  • Route by type: Use a switch on event.eventType to send different event types to different channels

You can also build more advanced workflows using orchestrations — chain multiple functions together, add conditional logic, or fan out to several endpoints in parallel.

What's Next

Start building your own workflow

Building something with Centrali and want to share feedback about this feature?

Email feedback@centrali.io