Outbound webhooks
This document describes outbound webhooks in WCKD Forms: HTTPS POST requests with JSON payloads that your server sends when a lead is created or when its status changes. Use them to connect Zapier, Make, n8n, HubSpot, Salesforce, Slack, WhatsApp bridges, or your own code.
Not email. Staff notification email is separate. See Notifications.
What is a webhook? (30-second version)
A webhook is a message your WCKD Forms server sends out when something happens. It is not a button in HubSpot and it is not a plugin inside WCKD Forms.
- Something happens in WCKD Forms (new lead saved, or someone changes a lead’s status).
- WCKD Forms makes an HTTPS POST request to a URL you paste in the dashboard.
- That URL usually belongs to Zapier, Make, or n8n — they “catch” the JSON.
- They connect to HubSpot, Salesforce, Slack, Google Sheets, etc. WCKD Forms never logs into your CRM for you.
Think of it as: WCKD Forms knocks on Zapier’s door with a JSON package; Zapier decides what to do with it in HubSpot.
The three parts you are wiring together
| Part | Who runs it | Your job |
|---|---|---|
| 1. WCKD Forms | Your PHP server | Turn on webhooks, paste the catch URL, pick when to send (see two events below). |
| 2. Middle tool | Zapier, Make, n8n, or your code | Create a Catch Hook / Custom webhook / Webhook trigger and copy its https:// URL. |
| 3. Destination | HubSpot, Salesforce, Slack, Sheets… | Add an action in the middle tool and map fields (e.g. fields.wf_email → Email). |
Order that works. Set up part 2 first (get the catch URL), then part 1 (paste URL in WCKD and save), then test, then part 3 (CRM action). If you paste a URL before Zapier is ready, nothing will listen.
Two webhook events
Every payload includes an event field. The dashboard maps UI controls to these values:
event value |
Setting in Operations | When WCKD sends it |
|---|---|---|
submission_created |
When a submission is received (checked) | After the row is saved to MySQL and staff notification email is attempted. |
status_changed |
When status changes to — one or more status labels checked | When someone updates a lead’s status in Inbox and the new status matches a checked label. JSON includes previous_status. |
Leave all When status changes to boxes unchecked to skip status_changed for that destination. You can enable both events on the same URL — branch on event in your automation.
Which event should I use?
| You want… | Use |
|---|---|
| Every form fill goes to Slack or a spreadsheet immediately | submission_created only — check When a submission is received |
| Only send leads to HubSpot/Salesforce after a human marks them Won | status_changed only — check Won under When status changes to |
| Alert on every fill, but CRM only on Won | Two destination rows: same or different URLs; one row for each event type |
The lead is always saved in your database first. If the webhook or CRM fails, the row is still in Inbox.
What webhooks are not
- Not a HubSpot/Salesforce connection inside WCKD Forms — there is no “Connect HubSpot” button. You connect HubSpot inside Zapier, Make, or n8n.
- Not inbound — CRMs do not call WCKD Forms. WCKD Forms calls your catch URL.
- Not email — webhooks do not replace staff notification email.
- Not shop/licence webhooks — Stripe checkout on the marketing site is unrelated to form
submission_created/status_changed. - Not retried automatically — failed POSTs are logged only; WCKD does not queue retries. Fix the URL or tool and trigger again (e.g. change status again for
status_changed). - 6 second timeout — each POST must complete within about six seconds. Long CRM calls belong in your middle tool or endpoint, not inside the webhook handler.
Setup checklist (do these in order)
- Middle tool: Create Zapier Catch Hook, Make Custom webhook, or n8n Webhook (POST). Copy the
https://URL. - WCKD Forms: Settings → Operations → open accordion Outbound webhooks.
- Check Enable outbound webhooks (master switch).
- Paste URL under HTTPS URL (up to 10 destinations).
- Check When a submission is received and/or one or more labels under When status changes to.
- Optional: Only these forms — limits by form template label in the UI. At dispatch time WCKD compares against the embed placement label (
form_namein JSON), not the registry key. Leave all unchecked to include every form, or ensure your secondwckd_form()argument matches the label you check. - Optional: Bearer secret — same value your receiver expects in
Authorization: Bearer …; stored server-side in private config. - Click Save on the Operations page.
- Test: submit a form (for
submission_created) or change a lead’s status in Leads (forstatus_changed). Confirm the middle tool received JSON. - CRM action: In Zapier/Make/n8n, add HubSpot, Salesforce, Slack, etc. and map
fields.*.
URL rules. Must be https://. localhost and private IPs are rejected. Your WCKD server must be able to reach the public internet to POST out.
What WCKD sends (the JSON package)
Every webhook is one POST with header Content-Type: application/json. Body is JSON. If you set a bearer secret, WCKD also sends Authorization: Bearer YOUR_SECRET.
All fields (both events)
| JSON key | Meaning |
|---|---|
event | Either submission_created or status_changed — read this first in your automation |
submission_id | Unique lead ID in your database — use to avoid duplicate CRM records |
form_name | Placement label from embed (second argument to wckd_form()), e.g. “Homepage contact” |
status | Current lead status (e.g. Pending, Won) |
submitted_at | When the visitor originally submitted |
page_url | Page URL when available |
ip_address | Visitor IP |
fields | Object of answers — keys like wf_email, wf_name, wf_message |
previous_status | Only when event is status_changed — status before the change |
Example: submission_created (new lead)
Sent when When a submission is received is checked and someone submits a form.
{
"event": "submission_created",
"submission_id": 42,
"form_name": "Homepage contact",
"status": "Pending",
"submitted_at": "2026-05-18 14:30:00",
"page_url": "https://example.com/contact",
"ip_address": "203.0.113.10",
"fields": {
"wf_name": "Alex",
"wf_email": "alex@example.com",
"wf_message": "Hello"
}
}
Example: status_changed (qualified in inbox)
Sent when at least one label is checked under When status changes to and someone updates status in Inbox. Note previous_status.
{
"event": "status_changed",
"submission_id": 42,
"form_name": "Homepage contact",
"status": "Won",
"previous_status": "Pending",
"submitted_at": "2026-05-18 14:30:00",
"page_url": "https://example.com/contact",
"ip_address": "203.0.113.10",
"fields": {
"wf_name": "Alex",
"wf_email": "alex@example.com",
"wf_message": "Hello"
}
}
In Zapier/Make/n8n, map CRM fields from fields.wf_email etc. Filter on event equals status_changed before creating a HubSpot contact if you only want qualified leads.
Delivery behaviour
| Topic | Behaviour |
|---|---|
| Method | POST with Content-Type: application/json |
| Timeout | About 6 seconds total (4 second connect timeout) |
| Retries | None — one attempt per event |
| Response status | WCKD logs curl failures; it does not validate HTTP status codes from your endpoint |
| URL rules | https:// only; localhost and private IPs rejected |
| Auth | Optional Authorization: Bearer YOUR_SECRET when a bearer secret is set |
| Failure logs | PHP error log prefix [wckd-forms webhook] |
Return HTTP 200 quickly from your endpoint. Heavy work (CRM API calls, WhatsApp sends) should run after you respond.
Zapier (step by step)
- Create a Zap → trigger: Webhooks by Zapier → Catch Hook.
- Copy the hook URL (
https://hooks.zapier.com/…). - WCKD: Settings → Operations → Outbound webhooks → enable → paste URL → check the right event box(es) → Save.
- Submit a test form. In Zapier, click to load the sample — you should see
eventandfields. - Add action (e.g. HubSpot — Create Contact). Map
fields Emailor pick from the trigger payload. - If one URL gets both events: add a Zapier Filter —
eventexactly matchessubmission_createdorstatus_changed. - Turn Zap on.
Make (step by step)
- New scenario → first module: Webhooks → Custom webhook → Add → copy URL.
- Paste into WCKD Operations, enable events, Save.
- Submit test form or change lead status — Make shows the data structure.
- Add next module (CRM, Slack, Sheets). Map from the webhook module output.
- Run scenario once, then turn scheduling on.
n8n (step by step)
- New workflow → Webhook node, method POST, copy Production URL.
- Paste into WCKD, Save Operations.
- Activate workflow (or listen in test), then trigger from WCKD.
- Add nodes (HubSpot, IF on
event, etc.). Bearer: check header in a Code node if you use a secret.
Your own HTTPS endpoint
For Node, PHP, Python, etc. on a server you control:
- Accept
POST, read raw body,json_decode/JSON.parse. - Switch on
body.event:submission_createdvsstatus_changed. - Return HTTP
200quickly. - Optional: require
Authorization: Bearermatching Operations. - Use
submission_idto dedupe CRM creates.
Failed POSTs log on the WCKD host as [wckd-forms webhook] in the PHP error log.
HubSpot, Salesforce, Slack, Pipedrive, Sheets
Always: WCKD → middle tool → CRM. OAuth for HubSpot/Salesforce lives in Zapier/Make/n8n, not in WCKD Forms.
HubSpot
- Trigger: Catch Hook / Custom webhook / n8n Webhook (from WCKD).
- Action: Create Contact (or Deal).
- Map
fields.wf_email, name fields, message to notes. - Qualify-first pattern: only check labels under When status changes to (e.g. Won) — leave When a submission is received unchecked for that URL.
Salesforce
- Action: Create Lead or Contact.
- Map from
fields; set a default Company in the automation if the form does not collect it.
Pipedrive
- Action: Create Person or Deal; map email, phone, message from
fields.
Slack
- Easy: Zapier/Make/n8n → Send Channel Message using
form_name+fields. - Alternative: Slack Incoming Webhook URL as a custom HTTP step in Make/n8n (you build Slack’s JSON format there).
Google Sheets, Airtable, etc.
Same pattern: webhook trigger → add row. Branch on event if you need different sheets for new vs qualified leads.
Troubleshooting
Nothing arrives at Zapier/Make/n8n
- Is Enable outbound webhooks checked?
- For that row, is When a submission is received checked, or at least one When status changes to label?
- Did you click Save on Operations after editing?
- Is the URL
https://and publicly reachable (not localhost)? - For
status_changed, did you change a status in Inbox? Submitting a form alone only firessubmission_created. - If When status changes to has boxes checked, the new status must match one of them (e.g. Won).
- If Only these forms has boxes checked, the submission’s
form_name(placement label) must match — see setup checklist.
CRM gets every lead (I only want Won)
- Uncheck When a submission is received for that URL.
- Check only Won under When status changes to.
- In Zapier, add filter
event=status_changedandstatus= Won.
401 Unauthorized
Bearer secret in WCKD does not match what your endpoint or middleware expects. Leave secret blank on both sides to test, then set the same value in both places.
Missing field in CRM
Open a test payload in Zapier/Make and confirm the key exists under fields (e.g. wf_phone). Custom fields must be in your form schema and allowed_columns.
Duplicate CRM records
Use submission_id in your automation to update instead of create, or search-by-email before create.
Related pages
- Notifications — email only (not webhooks).
- Operations — where outbound webhooks live.
- Inbox & leads — change status to fire
status_changed. - Troubleshooting — install and submit issues.