Google Forms × Slack — webhook spec
The delivery layer of the integration, incoming-webhook contract, payload shape, retry semantics, idempotency. Read this when you want to know exactly what bytes hit Slack and what happens when they don't.
- Slack incoming webhook (no app install)
- JSON payload, mrkdwn or Block Kit
- Auto-retry with exponential backoff
The webhook contract
https://hooks.slack.com/services/…text, icon_emoji, username, blocks, attachmentsExample rendered payload
POST https://hooks.slack.com/services/T0/B0/XXX
Content-Type: application/json
{
"icon_emoji": ":inbox_tray:",
"username": "RouteForms",
"text": "*New lead*. Acme Corp\n*Name:* Jane Doe\n*Email:* jane@acme.com"
}Slack responds ok (200) on success. Any non-2xx triggers retry or failure logging per the rules below.
Retry and idempotency semantics
- Retry trigger
- HTTP 5xx, HTTP 429
- Backoff
- 2s → 6s → 18s → 54s → cap
- No retry on
- 4xx (except 429)
- Idempotency key
- Google Forms response ID
- Failure alert
- After 3 consecutive failures (paid)
- Audit
- Delivery log, payload + status + retries
What Slack will tell you when it rejects
invalid_payload: JSON didn't parse or required field missing. Often a stray brace from template editing. Decode via /tools/slack-webhook-error-decoder.channel_not_found: channel deleted or archived. Re-create webhook bound to the new channel.no_service/ 404, webhook URL revoked or regenerated by the workspace admin. New URL needed.rate_limited(429), too many posts to the same workspace in a short window. RouteForms retries; if it persists, you're likely fanning out to too many channels per minute.
Three steps
- 1Create the Slack incoming webhookSlack → Settings & administration → Manage apps → Incoming Webhooks. Pick the channel, copy the URL.
- 2Paste the webhook URL into RouteFormsOn the form's settings tab in the RouteForms dashboard. Stored encrypted; displayed masked thereafter.
- 3Install the Apps Script and submit a test responseVerify the delivery log shows DELIVERED with HTTP 200 OK. Done.
Frequently asked questions
What does Slack expect at the webhook URL?▾
A POST with Content-Type application/json and a JSON body. The minimum body is {"text": "hello"}. For rich messages, the body is either Slack mrkdwn (text + extras like icon_emoji, username) or a Block Kit blocks array. RouteForms renders the message from your template and POSTs the resulting JSON; you see the exact bytes in the delivery log.
How does RouteForms know to retry?▾
On a 5xx response or a 429 (rate limit), the delivery is retried with exponential backoff — 2s, 6s, 18s, 54s, then a final cap. Permanent failures (404 channel not found, 400 invalid payload) aren't retried; they're logged with the error and surface in the failure-alert email after 3 consecutive failures (paid plans).
What stops duplicate posts on retry?▾
The Google Forms response ID. Every submission carries a unique response ID, and RouteForms tracks it through the whole pipeline. If a retry races with the original (rare; usually only on partial network failures), the second delivery sees the response ID is already DELIVERED and short-circuits. The Slack channel sees exactly one post per real submission.
Can I use a Block Kit payload instead of plain text?▾
Yes. The template editor accepts either mrkdwn or Block Kit. For Block Kit, paste the blocks array; RouteForms renders {{placeholders}} inside it and POSTs the resulting JSON. The Slack Block Kit payload generator (linked below) is the fastest way to build the JSON visually.
What does the delivery log capture about each webhook POST?▾
The Google Forms response ID, the matched routing rule (if any), the rendered payload JSON, the HTTP status code Slack returned, the Slack response body, the timestamp, the number of retries, and the final status (DELIVERED / FAILED / SKIPPED). Click a row to see the full payload, useful when the Slack rendering doesn't match expectations.
Ship the webhook integration in 3 minutes
Free for 30 responses a month. No card. Delivery log on every plan.
Keep reading
The integration at a glance, trigger, action, fields, setup.
Conditional routing layered on top of the webhook delivery.
Long-form guide covering the manual Apps-Script-only path too.
Paste a webhook URL; we POST a test payload and report Slack's response.
Build the Block Kit JSON visually; paste into the template editor.