ViablyViably
๐Ÿ“กWebhook Relay

Forward Stripe events to Slack in seconds

Viably's Webhook Relay accepts Stripe webhooks, formats them into clean Slack messages, and posts them to your channels along with periodic report cards so revenue tracking in Slack is effortless and automatic.

Stripe to Slack in 3 steps

Step 1

Create a Stripe Transactions relay

From Viably, create a relay endpoint and select Stripe Transactions in the dropdown. This helps Viably expect Stripe-formatted payloads and to route them to the right Slack message template.

Step 2

Add Webhook Destination in Stripe

In your Stripe dashboard, add a new Webhook Destination with the Viably query-param URL. Select charge.succeeded, invoice.paid, and optionally customer.subscription.updated for cancellation alerts.

Step 3

Copy the signing secret back to Viably

Viably needs the Stripe signing secret to verify incoming requests. Copy it from the Stripe dashboard and paste it into your relay endpoint's config in Viably.

Stripe Integration (Detailed Instructions)

Viably can receive events directly from Stripe and post them to Slack. Because Stripe webhook destinations post to a plain URL, you must use the query-param token format โ€” not the Bearer authorization header.
  1. 1

    Create a relay endpoint

    In the Viably dashboard, create a new relay endpoint with Stripe Integration enabled. Once created, open the token dialog and copy the Stripe Webhook Destination โ€” it looks like https://hq.viably.app/relay?token=โ€ฆ.

  2. 2

    Create a webhook destination in Stripe

    In your Stripe Dashboard, go to Developers โ†’ Webhooks โ†’ Add destination. Paste the Viably query-param URL as the Endpoint URL. Select these events: charge.succeeded, invoice.paid, and optionally customer.subscription.updated.

    charge.succeeded captures all successful transactions in Slack โ€” whether from Stripe Checkout or your own API integration. invoice.paidenriches each charge card with the customer's name, email, phone, and country. customer.subscription.updated is optional โ€” it fires a cancellation recovery alert when a subscriber schedules their cancellation, so your customer care team can reach out before the billing period ends.

    Do not send other Stripe events to this endpoint โ€” Viably silently drops unrecognised event types, but sending them unnecessarily adds noise to your webhook logs.

  3. 3

    Copy the signing secret

    After saving, Stripe displays a signing secret beginning with whsec_. Copy it to complete your setup on Viably. If you miss it, you can reveal or roll it from the destination details page.

  4. 4

    Complete setup in Viably

    Back in the Viably dashboard, click Edit on the relay endpoint. Paste the whsec_โ€ฆ value into the Stripe webhook secret field and save. Viably will now verify every incoming Stripe request and reject anything unsigned.

  5. 5

    Test it

    Use Stripe's Send test event button on the destination page to fire a sample event. Check your configured Slack channel โ€” you should see a formatted message within a few seconds.

Why the query-param URL? Stripe webhook destinations send a plain POST โ€” they do not support custom Authorization headers. The ?token=โ€ฆ format is the Viably-supported alternative for these integrations. Both URLs are shown in the token dialog after endpoint creation.
EventHow Viably renders it
charge.succeededrequired
Transaction card โ€” amount and charge time as title, customer name (with country flag) as subtitle, email, phone, plan, subscription period in the body. In batch mode, each charge gets its own swipeable card in a carousel.
invoice.paidrequired
Enriches the matching charge.succeeded card with customer name, email, phone, country, plan nickname, and billing period. In non-batch mode, also caches customer contact details (keyed by Stripe customer ID) for up to 90 days to enrich subscription cancellation alerts.
customer.subscription.updatedoptional
Posts a cancellation recovery alert when a subscriber schedules cancellation (cancel_at_period_end flips false โ†’ true). Shows customer name, email, phone, plan, billing period, and churn reason. Duplicate events are silently dropped. New activations and generic updates are also forwarded.

charge.succeeded โ€” Transaction fields

Viably reads the charge object at data.object and maps the following fields into a Transaction card in Slack. Every field is optional โ€” Viably renders what it can find and omits the rest.
Stripe fieldShown asNotes
data.object.amountAmountDivided by 100 โ€” Stripe stores amounts in the smallest currency unit (e.g. cents)
data.object.currencyโ€”Used for currency formatting; defaults to USD if absent
data.object.descriptionProduct
data.object.billing_details.nameNameFalls back to data.object.customer_email
data.object.billing_details.emailEmailFalls back to data.object.customer_email
data.object.billing_details.phonePhone
data.object.billing_details.addressLocationcity and country joined โ€” e.g. "Singapore, SG"
data.object.payment_intentPayment Intent
data.object.metadata.*VariousSelected keys from the Stripe metadata map โ€” see below

Recognised metadata keys

Viably scans data.object.metadata and surfaces the following keys as labelled fields in the Slack card. When multiple key aliases are listed, the first non-empty one wins. Any other metadata key is silently ignored.

metadata key(s)Shown as
discountDiscount
eventName, eventEvent
orderId, order_idOrder ID
typeType
ticketsTickets
voucherCode, voucherVoucher
descriptionDescription
productProduct
tierTier

customer.subscription.updated โ€” Subscription events

Viably classifies each subscription event as a cancellation scheduled, new activation, or generic updateโ€” each with its own Slack heading and emoji. The most actionable scenario is a scheduled cancellation: Viably posts a recovery alert with the customer's full contact details and a deadline for your customer care team to reach out before the billing period ends.
Stripe fieldShown asNotes
data.previous_attributes.cancel_at_period_end: false โ†’ data.object.cancel_at_period_end: trueHeadingTriggers the recovery alert: "๐Ÿšซ Cancellation Scheduled". Only fires on the specific false โ†’ true flip โ€” not on subsequent events where it is already true.
data.object.customerCustomerEnriched from cached invoice.paid data when available (shows name with country flag, email, phone). Falls back to bare Stripe customer ID (cus_โ€ฆ) if no invoice.paid was ever received for this customer.
data.object.items.data[0].price.nicknamePlanFalls back to lookup_key, then product ID
data.object.items.data[0].price.unit_amount + currency + recurring.intervalPriceFormatted as e.g. "$59.00 / monthly" or "$99.00 / every 3 months". unit_amount divided by 100.
data.object.items.data[0].current_period_start + current_period_endCurrent PeriodFormatted in workspace timezone. The recovery alert leads with 'Reach out before {end date}' to give the team a clear deadline.
data.object.cancellation_details.feedback / reason / commentFeedback / Reason / CommentEach field is shown only when non-null. feedback and reason are capitalised (e.g. 'Too expensive', 'Cancellation requested').
data.previous_attributes.status (incomplete / trialing) โ†’ data.object.status: activeHeadingTriggers "๐ŸŽ‰ New Subscription Activated" when a trial or incomplete subscription becomes active.
data.object.current_period_endPeriod endsShown on generic (non-cancellation, non-activation) subscription updates.
Deduplication. Stripe often fires 4โ€“5 customer.subscription.updated events for a single user action, and some carry cancel_at_period_end: true in both the current and previous attributes (not a new cancellation). Viably drops those silently โ€” only the event where cancel_at_period_end transitions from false to true triggers the recovery alert. New activations and other subscription updates are collapsed into one Slack message per subscription within a 90-second window.

Periodic reporting

When batch mode is enabled on a Stripe Transactions relay, Viably accumulates events over a configurable window and posts a single summary card to Slack โ€” rather than one message per transaction.

Period label

A 1-day window shows a single date (e.g. Apr 25). A multi-day window shows a date range (e.g. Apr 19 โ€“ Apr 25). All dates are rendered in your workspace's configured timezone.

Revenue sparkline

When events span more than one time bucket, a bar sparkline (e.g. โ–โ–‚โ–„โ–‡โ–ˆโ–…โ–‚โ–) shows the relative revenue distribution across buckets at a glance โ€” taller bars mean more revenue in that slot.

Transaction carousel

Up to 20 charges are shown newest-first as swipeable cards. Each card's title is the amount, subtitle is the customer name (or email), and the body shows email, phone/location, plan, subscription period, and charge time. If the batch has more than 20, a footer note shows the remaining count.

Unsupported events

Any Stripe events other than charge.succeeded and invoice.paid that arrive at this endpoint are acknowledged (not dropped) but excluded from the revenue count. Their event type names are listed in a footer warning on the batch card.

Report header. The batch card header shows the transaction count and endpoint name (e.g. 5 Transactions โ€” My Stripe Relay), with a Total Revenue and Transactions stats section directly below for visual hierarchy. Stripe charges are de-duplicated by charge ID before the total is calculated, so retried or re-delivered webhooks are never double-counted.