Skip to content

Webhooks

A webhook sends each submission, as JSON, to an address you choose. Services such as Zapier, Make and Google Apps Script give you that address and then pass the data on to a CRM, a spreadsheet or a chat channel.

  • Each submission should create a record in another system.
  • For a spreadsheet without a paid service, see Google Sheets.
  • For work that runs on your own site, such as copying uploads to Google Drive, FlowMint Workflows reacts to submissions without a webhook.
  1. Get the webhook address from the receiving service (in Zapier, Webhooks by Zapier → Catch Hook; in Make, a Custom webhook).
  2. Go to Form Entries → Forms and edit the form.
  3. Tick Enable webhook for this form.
  4. Choose the Destination: Google Sheets (Free), Zapier, Make (Integromat) or Custom Endpoint. Setup steps for that service appear below it.
  5. Paste the address into Webhook URL.
  6. Select Save Form. A Webhook Secret is generated.
  7. Select Test Connection to send a test request. The result shows the response code, the time it took and the response.

On a saved form, Preview Payload shows the JSON your endpoint will receive, built from the form’s fields with sample values.

Webhook settings belong to the saved form, not to its JSON. Forms created by an AI assistant through the connector can have them too; forms registered in PHP cannot.

A POST with a JSON body:

{
"event": "form_submission",
"timestamp": "2026-09-19T14:30:00+00:00",
"form": {"id": "quote", "title": "Get a Quote"},
"entry": {"id": 123, "submitted_at": "2026-09-19T14:30:00+00:00"},
"data": {"name": "Maya Chen", "email": "maya@example.com", "service": "repair"},
"files": [
{"field_key": "photo", "file_name": "roof.jpg", "file_size": 245112,
"mime_type": "image/jpeg", "file_url": "https://example.com/wp-content/uploads/2026/09/…"}
],
"site": {"name": "My Site", "url": "https://example.com"}
}

data uses the field keys. Fields hidden by a condition are left out.

For dropdowns, radio buttons and checkboxes, data holds either the stored option value (repair) or its label (Repair or service):

DestinationSends
Google Sheets (Free)labels
Zapier, Make (Integromat), Custom Endpointvalues

To choose yourself, set "webhook_resolve_option_labels": true (labels) or false (values) in the form’s settings. Entries always store values.

Each request carries these headers:

HeaderContains
X-FRE-Signaturesha256= and the HMAC-SHA256 of the raw body, keyed with the form’s Webhook Secret
X-FRE-Eventform_submission, or webhook_test for Test Connection
X-FRE-TimestampWhen the request was sent, as a Unix timestamp

To verify, compute the HMAC of the body exactly as received and compare:

$expected = 'sha256=' . hash_hmac( 'sha256', $raw_body, $secret );
$valid = hash_equals( $expected, $_SERVER['HTTP_X_FRE_SIGNATURE'] ?? '' );

Regenerate makes a new secret; update your endpoint to match.

The webhook is sent right after the entry is saved, and the submission waits up to 5 seconds for an answer. Any response from 200 to 399 counts as delivered. A network error or a response of 400 or more is retried twice, 1 minute and then 5 minutes later, using WordPress’s scheduled tasks. The Webhook column on Form Entries shows Delivered, Pending, Retrying or Failed. Delivery records are kept for 30 days.

  • The address is refused on save. It must start with http:// or https://, and cannot point to localhost or a private network address. Use https://.
  • Redirects are not followed. A redirect response counts as delivered, but the request is not sent on to the new address. Use the final address.
  • Nothing is sent when entries are off. Webhooks fire only for stored entries; see store_entries in Creating forms.
  • File links are public. Anyone who sees a file_url, including in the receiving service’s logs, can download the file. For sensitive uploads a developer can return signed, expiring links from the pforms_webhook_file_url filter.
  • For developers: pforms_webhook_payload changes the body, pforms_webhook_request_args the request, and pforms_webhook_sent / pforms_webhook_failed fire after each attempt.