The webhook
The top-level structure shared by every delivery, and the shared object shapes inside data.
Every event shares one top-level structure. Only event and data vary. Every id in the payload is a stable UUID that is safe to store and reference. All timestamps are ISO 8601 in UTC and end in Z.
We announce every payload change in advance, in the changelog. New fields are additive; build your integration to ignore fields it does not recognize, so additions never affect it.
Attributes
iduuidUnique delivery id, stable across retries. Use it to deduplicate.
eventstringThe event type.
form_submissionform_stepcompleted_leadpartial_leadbooked_callwebhookVersionstringThe version of the payload contract this delivery follows.
createdAtUtctimestampWhen the event happened, for example the moment the form was submitted. If a delivery is retried, this keeps its original value, so it is not the time the HTTP request was sent.
agencyobjectThe agency the subaccount belongs to.
+Show child attributes
iduuidnamestringsubaccountobjectThe subaccount that owns the webhook and the form.
+Show child attributes
iduuidnamestringformobjectThe form the event happened on.
+Show child attributes
iduuidnamestringurlnullable stringdataobjectEvent-specific content. See the page for each event.
{
"id": "4b8e2f6a-9c3d-4e7b-a1f5-8d2c6b9e0a47",
"event": "completed_lead",
"webhookVersion": "2026-08-05",
"createdAtUtc": "2026-07-28T14:32:11.482Z",
"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": {}
}Request headers
| Header | Example | Meaning |
|---|---|---|
Content-Type | application/json | Body is JSON. |
User-Agent | ROASForm-Webhooks/1 | Identifies ROASForm. |
ROASForm-Event | completed_lead | The event type. |
ROASForm-Delivery | 4b8e2f6a-… | Same as the webhook's id. |
ROASForm-Attempt | 2 | 1 on the first try, higher on retries. |
ROASForm-Signature | t=1753712000,v1=5f8a… | HMAC signature. See Verifying signatures. |
Shared objects
These shapes appear inside data across events. A field that has no value is null, never omitted.
lead
The lead is the person, not the run: leads are matched across submissions by
email or phone within the subaccount. Contact fields captured by this submission
are merged into the saved record before delivery, so the object arrives as
complete as we know the person: a returning visitor's company from an earlier
form shows up even if this form never asked for it, tags accumulate across
runs, and createdAtUtc is when the person was first seen. For what this
specific run captured, read submission.answers.
iduuidnamenullable stringemailnullable stringphonenullable stringcompanynullable stringlocationnullable stringtagsstring[]timezonenullable stringAmerica/Chicago.countrynullable stringcreatedAtUtctimestamp{
"id": "3d9f7a25-6c1b-4e8d-a2f4-8b0c5d7e9f13",
"name": "Jane Doe",
"email": "jane@example.com",
"phone": "+15555550100",
"company": "Doe Fitness LLC",
"location": "Austin, TX",
"tags": ["hot-lead"],
"timezone": "America/Chicago",
"country": "US",
"createdAtUtc": "2026-07-28T14:29:03.114Z"
}submission
iduuidstatusstringpartialcompletequalificationstringThe qualification outcome of this submission, set by the ending reached;
none while partial.
nonequalifiedunqualifiedscorenumberstartedAtUtctimestampcompletedAtUtcnullable timestampnull while partial.endingnullable objectWhich ending screen the visitor reached: the exit path's identity.
Screen content and redirect URLs are builder configuration and are not
delivered. null while partial. If the ending had already been deleted
when the event fired, id is null and name/type come from the
values saved with the submission, so route on type, match exact endings on id, and treat
id: null as an ending that no longer exists in the builder.
+Show child attributes
idnullable uuidnamestringtypestringcalendarredirectsuccesslastSeenElementnullable objectThe question the visitor was on most recently, in the same shape as an
answers entry. For abandoned submissions this is where they stopped;
value, values, and score are null when that question was never
answered. Becomes null entirely if that question had already been
deleted when the event fired.
answersarrayOne entry per question the visitor answered or moved past, in the order
each was first recorded (the visitor's path through the form, which can
differ from the builder order when logic jumps). An entry with no answer
content (value null or empty, values null or empty) is a question
that was presented and left unanswered; questions the visitor never
reached don't appear at all. An answer edited later keeps its original
position. See the answer shape below.
appliedTagsstring[]Tags this submission applied.
utmDatanullable objectUTM parameters captured with the submission.
ipAddressnullable stringThe visitor's IP address.
userAgentnullable stringThe visitor's browser user agent.
answers[]
elementIdnullable uuidThe question element. null if the question had already been deleted
when the event fired; label, type, and the answer values are saved
with the answer, so they survive the deletion.
labelstringtypestringThe question's element type. Forms created long ago may also send the legacy
types single_select and multi_select.
nameemailphoneaddresswebsitetextlong_textshort_textmultiple_choicesingle_choiceimage_choicedropdownyes_noopinion_scaleratingnumberdatefile_uploadvaluenullable stringSingle-value answers. null for multi-select answers. Two types carry a
JSON-encoded string that needs a second parse: file_upload decodes to
{ url, name, size, type }, where url is a permanent public link to the
uploaded file (the payload carries the pointer, never the bytes, and the
link does not expire); a structured address decodes to the address
components alongside a formatted string.
valuesnullable string[]Multi-select answers. null otherwise.
scorenullable numberThe points this answer contributed. Only questions that participate in
scoring (at least one scoring rule targets them) carry a number, so 0
always means a scoreable answer that earned nothing. Everything else is
null: questions outside scoring, questions never answered, and answers
recorded mid-progress that scoring (which runs at contact capture and
submit) has not evaluated yet.
{
"id": "5a2c8e94-1f7d-4b3a-9e6c-4d8f0b2a6c71",
"status": "complete",
"qualification": "qualified",
"score": 40,
"startedAtUtc": "2026-07-28T14:26:40.207Z",
"completedAtUtc": "2026-07-28T14:32:11.482Z",
"ending": {
"id": "9c4b7d13-8e2a-4f6c-b1d9-7a3e5c8f2d46",
"name": "Qualified - Book a call",
"type": "calendar"
},
"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": "d2c8f5b1-7e4a-4d9c-a6f3-9b0e5d8c2a64",
"label": "What are your goals?",
"type": "multiple_choice",
"value": null,
"values": ["Lose weight", "Build muscle"],
"score": 10
}
],
"appliedTags": ["hot-lead"],
"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"
}Data freshness
Every delivery is a snapshot of the moment the event happened. The body is
captured when the event fires (the createdAtUtc moment) and frozen: later
changes, a renamed form, a lead updated by a newer submission, a rescheduled
appointment, a question deleted in the builder, never rewrite a delivery that
was already captured. Retries resend the same body byte for byte.
Because each delivery is point-in-time, the newest delivery for a
submission.id is the current state of that submission, and the lead object
inside it reflects everything known about the person up to that moment.

