Send Stripe Webhooks to Slack Without a Server (JavaScript Function)

Turn Stripe webhooks into Slack messages without a backend: point Stripe at a Webhook Relay endpoint, attach a 20-line JavaScript function that builds the Slack payload, and forward to the Slack incoming webhook.

Send Stripe webhooks to Slack without a server

Stripe webhooks can post straight into Slack if something rebuilds the payload on the way: Stripe sends an event object, Slack's incoming webhook only accepts { "text": "..." } or a blocks array. Webhook Relay does the rebuild with a small JavaScript function that runs on every request, so there is no backend to deploy. Setup takes about ten minutes.

Stripe  ──▶  Webhook Relay endpoint  ──▶  JavaScript function  ──▶  Slack incoming webhook
(event)       (permanent public URL)       (event → Slack message)    (message in channel)

Step 1: Get a Slack incoming webhook URL

In Slack, create an app at api.slack.com/apps, enable Incoming Webhooks, add one to the channel that should get payment notifications, and copy the URL. It looks like https://hooks.slack.com/services/T000/B000/XXXX. Full walkthrough: how to get a Slack webhook URL.

Step 2: Create the Webhook Relay endpoint

Open new public destination, paste the Slack URL as the destination, and note the input URL Webhook Relay gives you. That input URL is permanent; it is what you will hand to Stripe.

Step 3: Add the transformation function

On the output that points at Slack, choose Transform and create a function with this JavaScript:

// Stripe event → Slack message
const event = JSON.parse(r.body)
const obj = event.data && event.data.object ? event.data.object : {}

// Only forward the events we care about; drop the rest silently.
const wanted = {
  "payment_intent.succeeded": "💰 Payment received",
  "invoice.paid": "🧾 Invoice paid",
  "invoice.payment_failed": "⚠️ Invoice payment failed",
  "customer.subscription.created": "🎉 New subscription",
  "customer.subscription.deleted": "👋 Subscription cancelled",
}
const headline = wanted[event.type]
if (!headline) {
  r.stopForwarding()
  return
}

const amount = obj.amount_paid ?? obj.amount_received ?? obj.amount ?? null
const currency = (obj.currency || "").toUpperCase()
const money = amount === null ? "" : ` — ${(amount / 100).toFixed(2)} ${currency}`
const customer = obj.customer_email || obj.customer || "unknown customer"
const mode = event.livemode ? "" : " (test mode)"

r.setBody(JSON.stringify({
  blocks: [
    {
      type: "section",
      text: {
        type: "mrkdwn",
        text: `*${headline}${money}*${mode}\n${customer} · \`${event.type}\` · <https://dashboard.stripe.com/events/${event.id}|open in Stripe>`,
      },
    },
  ],
}))
r.setHeader("Content-Type", "application/json")
r.setMethod("POST")

What it does: parses the Stripe event, drops anything not in the wanted map, formats the amount from cents, and sets the request body to a Slack Block Kit message. Webhook Relay then delivers that request to the Slack URL, retries it if Slack is briefly unavailable, and logs the delivery.

Want a different message layout? Paste a sample Stripe event into the free webhook to Slack formatter, design the message visually, and copy the generated function.

Step 4: Point Stripe at the endpoint

In the Stripe dashboard go to Developers → Webhooks → Add endpoint, paste the Webhook Relay input URL, and select the events you listed in the function (or all events; the function filters). Save, then use Send test event for payment_intent.succeeded. The message appears in Slack within a second or two. If it does not, the request log in the Webhook Relay dashboard shows exactly what Stripe sent and what Slack answered.

Optional: verify the Stripe signature

Stripe signs every webhook. To reject forged requests, store the endpoint's signing secret as a secret service connection, read the Stripe-Signature header in the function, and compare the HMAC before building the message. The webhook signature guide has the exact check; the free Stripe signature verifier helps you debug it against a captured payload.

Also deliver the event to your own app

The Slack message is usually a side channel. Add a second output on the same bucket that points at your API, a BigQuery table, or your laptop during development: every Stripe event is delivered to all of them, each with its own optional function.

Alternatives

Stripe's own Slack app posts a fixed set of notifications with no customisation. Zapier and Make offer Stripe-to-Slack templates with per-task pricing. A Lambda or Cloudflare Worker gives full control if you want to host and operate it yourself. The comparison of webhook transformation tools covers when each makes sense.

Frequently asked questions

How do I send Stripe webhooks to Slack without writing a backend?

Create a Slack incoming webhook URL, create a Webhook Relay endpoint that forwards to it, and attach a JavaScript function that reads the Stripe event and sets the body to Slack's message format. Point Stripe's webhook endpoint at the Webhook Relay URL. Every matching Stripe event then appears in the Slack channel, with no server, Lambda or Zap to maintain.

Why can't Stripe post directly to a Slack incoming webhook?

Slack incoming webhooks only accept their own JSON shape, a text string or a blocks array. Stripe sends an event object with type, data.object and other fields, so Slack rejects it. Something in the middle must rebuild the payload; that is what the transformation function does.

Can I filter which Stripe events reach Slack?

Yes. In the function, check event.type and call r.stopForwarding() for anything you do not want, or configure only the events you need on the Stripe side. Typical choices are payment_intent.succeeded, invoice.paid, invoice.payment_failed and customer.subscription.deleted.

Does this verify the Stripe signature?

It can. Functions can read the Stripe-Signature header and verify the HMAC using the signing secret stored as a Webhook Relay secret, dropping requests that fail. The example keeps the function short; the verify-webhook-signature guide shows the HMAC check to add.

Can the same Stripe webhook also go to my own backend?

Yes. Add a second output on the same bucket pointing at your API, with or without a transformation. Webhook Relay fans one incoming Stripe event out to every output, including localhost or a private server through the relay agent.