Webhooks
Forward every form submission to any HTTP endpoint — Zapier, Make, your own server, Slack, Discord, your CRM. JSON payload, optional HMAC signature for verification.
Setup
- Dashboard → form → Edit
- Set Webhook URL to your endpoint (must be HTTPS)
- Save
Every successful submission to this form now also POSTs JSON to your URL, in parallel with the email send.
Payload format
POST https://your-server.com/webhook
Content-Type: application/json
User-Agent: JustForms/1.0
X-JustForms-Signature: a1b2c3... (if signing key set)
{
"formId": "contact-abc123",
"submissionId": "0193ee5a-4d3f-7e21-b9f6-...",
"data": {
"name": "Alex",
"email": "alex@example.com",
"message": "Hello"
},
"utm": {
"utm_source": "google",
"utm_medium": "cpc",
"gclid": "Cj0KCQ..."
},
"country": "US",
"createdAt": 1730000000000
}HMAC signature verification (Business plan)
Set WEBHOOK_SIGNING_KEY as a Worker secret. We include X-JustForms-Signature header on every webhook — hex HMAC-SHA256 of the request body.
Node.js verification
const crypto = require('crypto');
function verify(req) {
const sig = req.headers['x-justforms-signature'];
const expected = crypto
.createHmac('sha256', process.env.JUSTFORMS_WEBHOOK_KEY)
.update(req.rawBody) // raw bytes — don't use JSON.stringify
.digest('hex');
// constant-time compare
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}Python verification
import hmac, hashlib
def verify(raw_body: bytes, sig_header: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, sig_header)Retries
If your endpoint returns non-2xx, JustForms retries:
- Starter — single try, best effort
- Pro — 3 retries (1m, 5m, 30m back-off)
- Business — 3 retries + dead-letter queue accessible via dashboard
Your endpoint should respond within 10 seconds. Slower responses get queued for retry.
Common destinations
Zapier
Create a Zap → trigger "Catch Hook" → copy the webhook URL → paste in JustForms.
Slack
Slack → Apps → Incoming Webhooks → Add to Slack → choose channel → copy URL.
{ "text": "..." }). Use Zapier or Make as a transformer to convert our payload to Slack's format — or use a small Worker as proxy.Discord
Server settings → Integrations → Create Webhook → copy URL. Discord accepts { "content": "message" }. Same transformer caveat applies.
Custom server
Any HTTPS endpoint that returns 2xx within 10s. Recommended: validate the signature, write to your DB, return { ok: true }.