If you set up webhook endpoints in your developer settings, your endpoints will receive a POST request with an event object whenever a form is completed.
{
"id": "EMcUHi5K81vBcBSQafx9P3",
"type": "form.created",
"form": {
"id": "RCBrLQKLYAuMg5k9UGCSxC",
"reference": "ab0b12e2-979c-47be-97d8-acf614685d57",
"type": "w9Oct2018",
"data": {},
"signatures": []
}
}
A unique identifier for the event
A string indicating the type of event. Currently the only event that is sent via webhook is the type form.created.
A form object. See the form object reference for more information.
Nextform signs requests with a Nextform-Signature header which includes a timestamp and HMAC hash. This allows you to optionally verify that the events were sent by Nextform, not by a third party. Here is a sample implementation for secure webhook handling with Express and Node.js:
// Import crypto functions along with your other usual imports
const { createHmac, timingSafeEqual } = require('crypto')
router.post('/webhook', async (req, res, next) => {
try {
// The signature is delivered in the format t=1492774577,s=5257a869e7ecebe...
// where t= is the timestamp and s= is the signature hash
// This helper function gets the timestamp and hash from the header
function parseSignature(signature) {
if (typeof signature !== 'string') return [null, null]
const values = signature.split(',')
const timestamp = values.find((s) => s.startsWith('t='))?.replace('t=', '')
const hash = values.find((s) => s.startsWith('s='))?.replace('s=', '')
return [timestamp, hash]
}
// Get the timestamp and hash. You may want to add handling for null/undefined values
const [timestamp, hash] = parseSignature(req.get('Nextform-Signature'))
// Now recalculate the signature by joining the timestamp and request body with a dot
const payload = timestamp + '.' + JSON.stringify(req.body)
const recalculatedHash = createHmac('sha256', SECRET).update(payload).digest('hex')
// Verify the signature use a timing safe comparison algorithm
const isTrusted = timingSafeEqual(Buffer.from(hash), Buffer.from(recalculatedHash))
if (!isTrusted) return res.status(401).send('Invalid signature.')
// Add your code to handle the data from the webhook and send a 200 OK response
res.end()
} catch (err) {
next(err)
}
})
If a 2XX or 3XX response is recieved from your server, the event will be considered successfully delivered. If no response or a bad response is received, delivery will be retried for up to 24 hours with an exponential back off.