Skip to content

Webhooks

Send quiz data to your own endpoint, Zapier, Make or n8n. Setup, the default URL, the exact payload and event field, background delivery, retries and fixes.

A webhook sends a JSON message to a URL you choose whenever something happens in a quiz. You can use it to push leads and results into a spreadsheet, a CRM or any automation tool.

Webhooks are set up per quiz, and you can also set a default URL for all quizzes.

Set up a webhook

  1. Open Quiz Builder, then All Quizzes, and edit the quiz.
  2. Open the Integrations tab.
  3. On the Webhook card, turn on the toggle. The card shows a Connected badge.
  4. Paste your endpoint into Webhook URL, for example https://hooks.example.com/quizably.
  5. Select Send test to check the connection. A successful test shows Test delivered with HTTP 200. A failure shows Test failed.
  6. Save the quiz (Save or Next).

Use one URL for every quiz

If most of your quizzes send to the same place, set a default instead:

  1. Open Quiz Builder, then Integrations.
  2. On the Webhook card select Configure (or Edit webhook once one is set).
  3. Paste the address into Default webhook URL and select Save webhook. Leave it blank to turn the default off.

The address must be a valid http or https URL, otherwise it is not saved. The default applies to every quiz that has no webhook of its own: a quiz that has its own URL keeps it, a quiz whose webhook toggle you switched off stays off, and a quiz with the toggle on but a blank URL uses the default.

When a webhook is sent

Every message has the same shape. The event field tells you which kind it is.

eventWhen it is sentleadresult, score, breakdown
lead_capturedThe visitor submits your lead form. With double opt-in, when the visitor clicks the confirmation link instead.Filled inFilled in only if the quiz was already scored, otherwise null
submission_completedThe visitor finishes the quiz and it is scoredFilled in if the visitor gave their details during that visit, otherwise nullFilled in

Things to know:

  • If the quiz has no lead form (Show the form set to Off), only submission_completed is sent, with lead set to null.
  • If the quiz has a lead form and the visitor fills it in, both messages are sent. The submission_completed message already contains the lead, so it is the complete record.
  • If the visitor skips an optional form, only submission_completed is sent.
  • If the same email is submitted again for the same quiz, a new lead_captured message is sent.
  • A survey or a quiz with no result configured sends result as null.

Payload

Every request is a POST with Content-Type: application/json.

{
  "event": "submission_completed",
  "quiz_uuid": "a1b2c3d4-0000-4000-8000-000000000000",
  "quiz_title": "What's Your Coffee Personality?",
  "quiz_type": "personality",
  "submission_uuid": "e5f6a7b8-0000-4000-8000-000000000000",
  "result": { "id": 12, "title": "The Flat White" },
  "score": null,
  "breakdown": { "tally": { "12": 4, "13": 1 }, "total_answers": 5 },
  "lead": { "id": 5, "email": "ann@example.com", "name": "Ann", "phone": null, "double_optin_verified": null },
  "timestamp": "2026-10-01T12:00:00+00:00"
}
FieldDescription
eventlead_captured or submission_completed.
quiz_uuidThe quiz’s unique ID (36 characters).
quiz_titleThe quiz title.
quiz_typepersonality, trivia, survey or poll.
submission_uuidIdentifies one visit. The same value appears in both messages for that visit.
result{ id, title } of the matched result, or null. The title is sent as stored and may contain HTML.
scoreThe trivia score. null for other quiz types.
breakdownDetails of the scoring. The shape depends on the quiz type, see below.
lead{ id, email, name, phone, double_optin_verified } or null. Free forms collect name and email, so phone is null.
timestampWhen the message was created, ISO 8601, UTC.

lead.double_optin_verified is true when the lead has confirmed, false when the quiz uses double opt-in and the visitor has not clicked yet, and null when the quiz does not use double opt-in.

The breakdown object depends on the quiz type:

Quiz typeBreakdown
Personality{ "tally": { "<result_id>": votes }, "total_answers": n }
Trivia{ "score": n, "correct_count": n, "total_questions": n }
Survey and poll{ "answered_questions": n, "total_questions": n }

The payload does not include individual answers, typed text, ratings, UTM values or the consent flag.

Sample: form submitted, quiz not finished yet

This is a quiz with the form at Before quiz. The visitor has just submitted the form and has not answered anything.

{
  "event": "lead_captured",
  "quiz_uuid": "a1b2c3d4-0000-4000-8000-000000000000",
  "quiz_title": "What's Your Coffee Personality?",
  "quiz_type": "personality",
  "submission_uuid": "e5f6a7b8-0000-4000-8000-000000000000",
  "result": null,
  "score": null,
  "breakdown": null,
  "lead": { "id": 5, "email": "ann@example.com", "name": "Ann", "phone": null, "double_optin_verified": null },
  "timestamp": "2026-10-01T12:00:00+00:00"
}

Sample: quiz completed

{
  "event": "submission_completed",
  "quiz_uuid": "a1b2c3d4-0000-4000-8000-000000000000",
  "quiz_title": "What's Your Coffee Personality?",
  "quiz_type": "personality",
  "submission_uuid": "e5f6a7b8-0000-4000-8000-000000000000",
  "result": { "id": 12, "title": "The Flat White" },
  "score": null,
  "breakdown": { "tally": { "12": 4, "13": 1 }, "total_answers": 5 },
  "lead": { "id": 5, "email": "ann@example.com", "name": "Ann", "phone": null, "double_optin_verified": null },
  "timestamp": "2026-10-01T12:00:04+00:00"
}

The test message from Send test is different. It contains only event (set to test), quiz_uuid, quiz_title and timestamp.

One record per visitor

The simplest setup is to act only on submission_completed and ignore lead_captured. That message carries the lead and the result together, and it is sent once per finished visit.

In an automation tool such as Zapier, Make or n8n:

  1. Create a webhook trigger and paste its URL into Webhook URL.
  2. Add a filter that continues only when event equals submission_completed.
  3. If lead is not empty, add the email and name to your list or sheet together with result.title and score.

Use lead_captured instead when you want leads from people who never finish the quiz. With a form before the quiz, that message arrives as soon as the form is sent. When you use both events, match them on submission_uuid with a “find or create” step, because retries can deliver messages out of order.

Note: With double opt-in on, submission_completed arrives before the visitor confirms and shows double_optin_verified as false. Subscribe people on lead_captured, or check that field first.

Delivery, timeouts and retries

Webhooks are sent in the background. When a quiz event happens, Quizably queues the delivery with WordPress cron and the visitor moves on at once, so a slow endpoint does not hold up the result screen. Each delivery waits up to 8 seconds for your endpoint to answer.

Note: Delivery depends on WP-Cron. If your site sets DISABLE_WP_CRON to true, queued webhooks are only sent when a real server cron job calls wp-cron.php. Without one, nothing is delivered.

The response code decides what happens next:

ResponseWhat Quizably does
Any 2xxCounts as delivered.
5xx, 429, a timeout or a connection errorRetries.
Any other 4xxTreats it as failed and does not retry.

Retries run up to 3 times, about 1, 2 and 4 minutes after the previous attempt (roughly 7 minutes in total, 4 attempts at most). This matches the help text under Webhook URL. Retries also use WordPress cron, so they need the site to receive traffic or have a working cron.

There is no delivery log and no failure alert. The Integration sync area in a lead’s detail panel stays empty. If you want to see what was sent, point the webhook at a request catcher while you test.

Developers can switch off the background queue and send during the visitor’s request with add_filter( 'quizably_integration_async', '__return_false' );. See Hooks and filters.

Testing with a request catcher

  1. Create a temporary URL with any public request catcher service.
  2. Paste it into Webhook URL and select Send test.
  3. Check that the catcher received the test message.
  4. Take the quiz yourself and watch for the real messages: one if there is no form, two if there is.
  5. Replace the URL with your real endpoint and turn the test URL off.

Security

  • Use an https:// URL. Certificates are verified, so a self-signed certificate fails.
  • Treat the URL as a secret. Anyone who has it can send fake data to your automation. Use a long, unguessable path if your tool allows it.
  • The free webhook does not sign requests. Do not assume a request is genuine because of its payload alone.
  • The payload contains personal data such as email and name. Only send it to services you trust.

Common problems

ProblemLikely cause and fix
Test failedCheck the URL for typos and that the endpoint accepts POST with JSON.
Nothing arrives from real visitsThe toggle is off, the quiz is a draft, or the URL points to localhost or a private network address. Those are refused. Use a public URL.
Lead arrives but no resultThat is the lead_captured message, sent before the quiz was scored. The result arrives in the submission_completed message.
Result arrives but lead is emptyThe visitor skipped the form, or the quiz has none.
Nothing arrives and the site sets DISABLE_WP_CRONQueued webhooks need a real cron job to call wp-cron.php.
No lead_captured message with double opt-in onIt is sent only after the visitor clicks the confirmation link.
Only one message per visitorThe form is Off, the visitor skipped it, or the visitor has not confirmed yet.

Last updated October 4, 2026.