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.