Send events from your site to Slack
- Trigger
- POST /relay
- Lands in
- The relay log, plus any channel you route to
- Setup
- 3 min
- Needs
- anything that can send a http POST

New signup from Dunder Mifflin
[email protected] · via My Site, Signup Page
- Type
- signups
- Plan
- pro
- Campaign
- spring-launch
- Submitted at
- 11:04 AM
The same POST shape carries every event type. Where each one lands, and how it batches, is decided per type in the dashboard.
Create a relay endpoint in the Viably dashboard and attach the Slack channels you want it to use.
Send a POST from your site or backend with the data for the event. Include a type field to route it correctly.
Viably formats the payload and posts it to Slack immediately or in a batched card, depending on how the type is configured.
Environment variables
After creating an endpoint in the dashboard, add these to your project's environment.
Both values are shown in the dashboard immediately after creating an endpoint. Your token is only displayed once, so store it somewhere safe.
TypeScript types
Drop this into your project as viablyTypes.ts. Each event type carries its own recommended fields, and Viably surfaces a hint in Slack when a recommended field is missing.
Sending a payload
A minimal helper and three common usage examples. Any additional fields you include beyond the recognised ones appear in the Slack message as extra context.
Event types
The type field routes the event to the matching Slack message template. If omitted or unrecognised it falls back to others. Viably adds an inline hint to the Slack message when a recommended field is absent.
transaction counts toward your revenue figures, ocris Viably's own document pipeline, and inbox and reply decide which side of a conversation an email sits on. Send one of these four as your type to a relay endpoint that was not built for it, and Viably treats it exactly as it treats any other unrecognised value. The event still reaches Slack under others, quietly, with no error returned but resulting in no contact or revenue captured from it.leadgen, signups, contactform, or transaction event does more than post to Slack. It creates or updates a contact, keyed on the email address, so the same person's enquiry, signup, and payment gather on one record you can work, answer, and attribute revenue to. See the Lightweight CRM guide for what that record does for you.leadgen, signups, contactform, and transaction, and all three are worth sending. email is the identity key your Contacts list is built on, so a lead captured in June and a payment in July resolve to the same person, and your periodic report can tell you how much revenue that lead eventually brought in. name and company are what turn that row into something a human can act on. Without them you still get the Slack message, but the contact arrives as a bare address with nobody to greet."My Site — Contact Page". Viably uses this for footer attribution on every message. If omitted, it falls back to the HTTP Referer or Origin header, then to the domain you set on the endpoint in the dashboard.new Date().toISOString(). Viably formats it using your workspace's default timezone and displays it as a Submitted at field in the Slack message. If omitted, no timestamp is shown.Duplicate events
event_id is optional, and it is the single most useful optional field on this page. It is your own identifier for the event a payload describes, and sending it is how you tell Viably that two deliveries are one event.
event_id and Viably remembers it for 24 hours, so the second delivery is dropped before any of that happens.order_id, and Stripe events on Stripe's own event id. For everything else it falls back to comparing the payload, and treats an identical body carrying the same email address inside ten minutes as one event. That window is deliberately short, because two identical bodies a week apart are usually one person genuinely signing up again, and a fallback cannot tell the difference. An event_id can, so Viably has something to reliably match on.signup:8814 is perfect.Calling
crypto.randomUUID() as you post the webhook is worse than sending nothing at all. A supplied event_id is taken as your word on which deliveries are the same event, so a fresh one per request means no two deliveries ever match.newsletter:[email protected]:2026-07-30. Subscribing twice in an afternoon is one subscription, coming back in March is a second, and that is exactly what the id then says. Avoid making it stable forever in this case, because Viably stores your id on the contact event under a unique index: somebody genuinely resubscribing next month would post to Slack and then be dropped from your CRM without a word.Custom event types
The six types above are the ones Viably ships with, and they are not the limit. Send type as any lowercase value that starts with a letter and uses only letters, digits, and underscores, up to 64 characters, and it works the first time you send it. support_ticket, plan_upgraded, and nps_response are all valid without asking anyone for permission first.
othersis, and it registers itself in your workspace's event catalog at the same time. What it does not do on its own is create or update a contact. An admin has to open that catalog and decide what the type means, whether it should capture a lead, a signup, or a customer, and whether your team is expected to reply, before it does anything beyond posting a message. A string a payload happens to carry should never be able to start writing into your Contacts or your revenue figures before a person on your team agreed that it should.type alone. See Routing multiple event types for how to send different types to different channels without touching your integration code.others, the same as a malformed one, so an integration never breaks outright over it.Reporting
Every event you deliver is recorded for reporting. In the Month in Review area of your dashboard, Viably charts your webhook volume by category, so you can follow how signups, transactions, and other event types move through the month.
Channel override
By default, events are posted to the Slack channels you configured on the endpoint. You can override this per event by including a channels array in your payload. If Viably cannot access any of the override channels, it falls back to the endpoint defaults automatically.
Channel IDs can be found by right-clicking a channel in Slack, choosing View channel details, and copying the ID at the bottom.
Routing multiple event types
One endpoint token is not limited to one kind of event. Send signups and a custom type like support_ticket through the same token, and both still reach Slack, because type alone decides which template renders an event. What differs, if you want it to, is not in your code at all.
support_ticket can post immediately to a support channel while signups keeps batching every six hours into a growth channel, and changing one never touches the other, even though both arrived through the same POST shape and the same bearer token.channels is something your code decides, request by request, and it always wins over everything else. Where each event lands is something an admin decides once, per type, from the dashboard, and it is what a type does by default when your payload does not name a channel override itself. Most integrations never need channels at all once routing is set up this way, since the decision already lives on the type rather than needing to be repeated on every send.What a batched card shows
A type that batches does not post one card per event. Viably holds the events for the interval you set, then posts the whole flush as one card with a sortable table in it. The columns are not a fixed list. They are built from the payloads in that flush, so the fields you send are the fields your team reads.
- Recognised fields come first.
name,email,company,amount,plan,statusand the rest of the vocabulary keep a fixed order, so two flushes of the same type read the same way. - Then your own fields. Any other value you send becomes a column, ranked by how many events in the flush carry it. A hackathon portal sending
team_nameandrequested_bygets a column for each. Nested objects and arrays are skipped, and so areevent_idandcontact_id, which are plumbing rather than news. titlenames the kind of event. One kind in the flush and it is stated once above the table. Several kinds and it becomes an Event column, with a count per kind above it.- Numbers stay numbers. A field whose every value is a number gets a column that sorts by size, so a score of 80 ranks above a score of 9 rather than beside it alphabetically. The When column carries the date as well, once a flush spans more than one day.
- A
sourceevery event shares moves to the footer. A mixed flush keeps it per row instead, where it is the fact that tells two otherwise identical rows apart.
message, which is placed last. A card holds seven columns and a hundred rows, ten to a page. Send more fields than that and the card names the ones it could not fit, so you can see what is missing and trim the payload. A flush that turns out to hold a single event posts the normal single-event card instead.Auto-create tasks
Every endpoint has an optional Spawn a task toggle in the dashboard. When it is on, each delivered event also creates a task, posted as a claimable card threaded under the Slack notification, so events that need follow-up always have an owner.
- Assign it, or leave it up for grabs. Route the task to a specific teammate, or leave it unassigned so anyone can claim it in Slack.
- It is a real task. The card carries Claim and Mark Done buttons, and the task shows up on your board, in the Weekly Digest, and in follow-ups, identically to a task created by a clipboard reaction.
- Non-Stripe endpoints spawn a task on every single non-batch delivery, one per lead, contact-form fill, signup, deploy, and so on.
Stripe Integration
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 rather than the Bearer authorization header.
- 1Create 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 or query-param URL. It looks like
https://hq.viably.app/relay?token=…. - 2Create 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 two events:
charge.succeededandcustomer.subscription.updated.charge.succeededin particular captures all your successful transactions in Slack, whether they originated from Stripe Checkout or from your own custom integration using Stripe's APIs. Viably looks for this event's payload to extract the correctamount,currency, anddescriptionto build your transaction messages in Slack.
You should not send any other Stripe events to this Webhook Relay endpoint, since that can cause an unexpectedly heavy load of messages in your workspace, and even double notifications or double-counting in revenue tracking. - 3Copy 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. - 4Complete 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. - 5Test it
Use Stripe's Send test event button on the destination page to fire a sample event. Check your configured Slack channel, where you should see a formatted message within a few seconds.
Authorization headers. The ?token=… format is the Viably-supported alternative for these integrations, and both URLs are shown in the token dialog after endpoint creation.Campaign attribution
Most teams can tell you how many people a campaign reached. Far fewer can tell you what those people went on to spend, because the campaign is recorded in the ad platform and the revenue is recorded somewhere else entirely, and nothing joins the two without somebody exporting both and reconciling them by hand. Viably closes that gap as a side effect of capturing the contact, and it asks nothing of you beyond the page URL your form already knows.
current_page_url in your payload and Viably reads utm_source, utm_medium, utm_campaign, utm_content, utm_term, utm_id, and utm_author off the query string your ad platform appended when the visitor clicked. If you post your own JSON and the URL is not to hand, send those fields directly and they are read the same way. Nothing else changes about your integration.fbclid, gclid, and the hsa_*cluster, are captured alongside the campaign rather than dropped. Each one shows up as its own entry under Captured data on the contact, ready to promote into a field the moment you want to match it against your ad platform's own reporting, so a new parameter from a new platform can be captured automatically without any additional setup.UTM source, UTM medium, and UTM campaign as columns beside the source, which is enough to pivot a spreadsheet by campaign and see what each one went on to earn without touching another tool. Contacts captured before you started tagging links carry empty cells, because the columns are fixed so that a file you built a pivot on keeps working next month.city, plan, or your own custom metadata. Viably renders them as additional context in the Slack message so nothing is lost. One of them earns special treatment: current_page_url is also read for campaign tags, which is covered above.Nothing. Viably hosts the endpoint, so your app only needs to send a single POST request.
Yes. The payload's type field picks the Slack template and routing, so one endpoint can handle signups, contact forms, deployments, and custom events.
Yes. Person events create or update a contact, so a signup, form submission, and payment can all land on the same record.
Yes. Each endpoint has default channels, and any payload can override them with a channels array.
Create your first endpoint from the Webhook Relay page. It takes one POST to see an event land in Slack.
Add Viably to Slack