form_step
A visitor made progress in the form.
Fires as a visitor makes progress: a question answered and moved past, or an earlier answer edited. Each delivery is a cumulative snapshot of everything captured so far, and rapid progress (several answers within a few seconds) coalesces into a single delivery carrying all of it. Don't count deliveries to measure answers; read submission.answers.
data.submission.lastSeenElement is the visitor's current position (usually the question just answered, though it can move backward when they revisit an earlier question), and data.submission.answers is everything answered so far, so each delivery is a cumulative snapshot rather than a single-field diff.
lead is null until the visitor supplies an email or phone; earlier steps still deliver, they just have no contact details yet. Merely seeing a question sends nothing; moving past one does, answered or not: a question skipped without an answer appears in answers with empty value and values.
Processing tip: treat every delivery as a cumulative snapshot and upsert by data.submission.id rather than inserting a row per delivery. The same question can legitimately fire more than once if the visitor edits an earlier answer, each time with a fresh delivery id, and rarely two deliveries with different ids can carry identical state. The upsert pattern absorbs both without any special handling.
data
leadnullable objectThe lead so far, or null before any contact details are given. See shared objects.
submissionobjectThe in-progress submission (status is partial). lastSeenElement is the visitor's current position and answers holds everything so far. Also carries ending, utmData, ipAddress, userAgent, and appliedTags. See the submission object.
splitTestVariantnullable object{ id, name } of the variant served, or null when the form has no running split test.
{
"id": "9a4d7f12-6b3e-4c8a-92f5-0e8b1c5a9d37",
"event": "form_step",
"webhookVersion": "2026-08-05",
"createdAtUtc": "2026-07-28T14:29:03.245Z",
"agency": {
"id": "c1a2b3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"name": "Acme Marketing"
},
"subaccount": {
"id": "7f3e9d21-4b8a-4c5e-9f60-2d8b1a7c3e54",
"name": "Acme Fitness Client"
},
"form": {
"id": "e8b4c672-9a1d-4f3b-b7c8-5d2e9f0a1b3c",
"name": "Fitness Coaching Application",
"url": "https://forms.roasform.com/fitness-coaching"
},
"data": {
"lead": {
"id": "3d9f7a25-6c1b-4e8d-a2f4-8b0c5d7e9f13",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": null,
"company": null,
"location": null,
"tags": [],
"timezone": "America/Chicago",
"country": "US",
"createdAtUtc": "2026-07-28T14:29:03.114Z"
},
"submission": {
"id": "5a2c8e94-1f7d-4b3a-9e6c-4d8f0b2a6c71",
"status": "partial",
"qualification": "none",
"score": 30,
"startedAtUtc": "2026-07-28T14:26:40.207Z",
"completedAtUtc": null,
"ending": null,
"lastSeenElement": {
"elementId": "a1d4c7f2-9b3e-4c6a-8d2f-5e9b1c4a7d30",
"label": "What is your email?",
"type": "email",
"value": "jane@example.com",
"values": null,
"score": null
},
"answers": [
{
"elementId": "b7e2f9a4-3c8d-4a1e-9f5b-6d0c2e8a4f17",
"label": "What is your monthly budget?",
"type": "single_choice",
"value": "$2,000 - $5,000",
"values": null,
"score": 30
},
{
"elementId": "a1d4c7f2-9b3e-4c6a-8d2f-5e9b1c4a7d30",
"label": "What is your email?",
"type": "email",
"value": "jane@example.com",
"values": null,
"score": null
}
],
"appliedTags": [],
"utmData": {
"utm_source": "facebook",
"utm_medium": "cpc",
"utm_campaign": "summer-2026"
},
"ipAddress": "203.0.113.42",
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15"
},
"splitTestVariant": {
"id": "d6f1a8c3-2e9b-4a5d-8f7c-1b4e6a9d3c82",
"name": "Variant B"
}
}
}
