Webhooks
Webhooks let you send form submission data to your own server or application in real time. This makes it easy to automate workflows, trigger custom logic, or integrate Formware with your internal systems.
How webhooks work
Section titled “How webhooks work”When someone submits your form, Formware sends a POST request to your webhook URL with the submission data in JSON format.
Each request includes:
- Form responses (
answers) - Field metadata (
fields) - Event details (ID, type, timestamp)
You can use this data to trigger actions like:
- Storing responses in your database
- Sending data to a CRM
- Running custom business logic
Set up a webhook endpoint
Section titled “Set up a webhook endpoint”To receive webhook events, you’ll need an endpoint that:
- Accepts HTTP POST requests
- Parses a JSON payload
- Returns a 2XX status code within 10 seconds
Add a webhook in Formware
Section titled “Add a webhook in Formware”Webhook setup via the UI will be available soon.
If you need access right away, please please Contact Support.
Secure your webhook (optional)
Section titled “Secure your webhook (optional)”You can secure your webhook by using a signing secret to verify that Fromware generated a webhook request and that it didn’t come from a server acting like Formware.
When enabled, each request includes a Formware-Signature header:
Formware-Signature: sha256=...This is a SHA256 hash of the request payload. You can validate it on your server before processing the data.
Example: Verify signature (Python / FastAPI)
Section titled “Example: Verify signature (Python / FastAPI)”from fastapi import FastAPI,Request,HTTPException
import hashlibimport hmacimport base64import os
app = FastAPI()
@app.post("/webhook")async def recWebHook(req: Request): raw = await req.body()
receivedSignature = req.headers.get("formware-signature")
if receivedSignature is None: return HTTPException(403, detail="Permission denied.")
sha_name, signature = receivedSignature.split('=', 1) if sha_name != 'sha256': return HTTPException(501, detail="Operation not supported.")
is_valid = verifySignature(signature, raw)
if(is_valid != True): return HTTPException(403, detail="Invalid signature. Permission Denied.")
# Do something with the payload received return {"Message": "Webhook well received"}
def verifySignature(receivedSignature: str, payload): WEBHOOK_SECRET = os.environ.get('FORMWARE_SECRET_KEY') digest = hmac.new(WEBHOOK_SECRET.encode('utf-8'), payload, hashlib.sha256).digest() e = base64.b64encode(digest).decode()
if(e == receivedSignature): return True return FalseWebhook retries
Section titled “Webhook retries”Automatic retries are not yet available. If this is critical for your use case, please Contact Support.
Webhook payload structure
Section titled “Webhook payload structure”Each webhook event includes the following fields:
event_id— Unique ID for the submissionevent_type— Event type (e.g.form_response)sent_at— Timestamp of the requestanswers— Map of field IDs to submitted valuesfields: an ordered list of fields containing the field id, field type and title. This is the order in which the questions had been asked in the form filled by respondents.
Example request
Section titled “Example request”POST /[endpoint_url] HTTP/1.1User-Agent: Formware WebhooksContent-Type: application/jsonFormware-Signature: sha256=...{ "event_id": "68ecc910636199413b7f8bd6", "event_type": "form_response", "sent_at": "2025-08-25T15:10:32.552718587+05:30", "answers": { "3b8c1343-e457-4945-bd09-8e529e4fb012": { "value": "https://dummy.com" }, "476604aa-ef34-4891-b88a-4f9b5e1baa2f": { "value": "+449998887777", "metadata": { "country_code": "GB" } }, ... }, "fields": [ { "block_id": "476604aa-ef34-4891-b88a-4f9b5e1baa2f", "block_type": "Phone Number", "title": "Phone number?" }, { "block_id": "3b8c1343-e457-4945-bd09-8e529e4fb012", "block_type": "Website", "title": "What is your website?" }, ... ]}