---
title: "A shopper finished a quiz"
method: POST
path: "quiz.finished"
tags: ["webhooks"]
---

# A shopper finished a quiz

`POST quiz.finished` (webhook)

About a minute after the session completes, with the answers, outcomes and products shown through that minute, and identities on endpoints with include_pii.

## Payload

- WebhookEventWebhookSession
  - `id` string, required: The event id, also sent as the webhook-id header; deduplicate on it
  - `type` string, required: The topic: quiz.started | quiz.finished | quiz.abandoned | identity.captured | quiz.published | experiment.started | experiment.ended | profile.created | profile.updated | export.completed | webhook.endpoint.disabled | ping
  - `created` string, date-time, required: When the event happened
  - `api_version` 'v1': The payload version
  - `data` WebhookDataWebhookSession, required
    - `object` WebhookSession, required
      - `id` string, required: The session's id, the same session_id the profiles API shows
      - `quiz_id` string, required: The quiz the session ran
      - `quiz_name` string, nullable, required: The quiz's name as the session's version carried it; null when the quiz was deleted before the delivery was built
      - `version_id` string, nullable, required: The version the session ran; null when that version row is gone
      - `version_number` integer, nullable, required: The number of that version; null when it is gone
      - `experiment_id` string, nullable: The A/B test the session was split into; null outside one
      - `arm_id` string, nullable: The arm the session was shown; null outside a test
      - `visitor_id` string, required: The shopper's browser: the persistent visitor, or a visitor of this session only until analytics consent is given
      - `started_at` string, date-time, required: When the session opened
      - `ended_at` string, date-time, nullable, required: When the session ended: finished, closed or idle for 30 minutes; null while it runs
      - `channel` string, required: How the shopper arrived: direct | organic_search | paid_search | organic_social | paid_social | email | sms | affiliate | display | paid_other | referral | ai_assistant | other | shared_results
      - `device` WebhookDevice, required
        - `class` string, required: mobile | tablet | desktop
        - `family` string, nullable, required: The device family; null when the user agent did not say
        - `vendor` string, nullable, required: The device vendor; null when the user agent did not say
        - `model` string, nullable, required: The device model; null when the user agent did not say
        - `browser` string, nullable, required: The browser; null when the user agent did not say
        - `browser_version` string, nullable, required: The browser version; null when the user agent did not say
        - `os` string, nullable, required: The operating system; null when the user agent did not say
        - `os_version` string, nullable, required: The operating system version; null when the user agent did not say
      - `country` string, nullable, required: The shopper's country from their IP, ISO 3166-1 alpha-2; null when unknown
      - `page_url` string, nullable, required: The page the session opened on, origin and path without the query string; null when the embed did not report one
      - `utm_source` string, nullable, required: The utm_source of the page the session opened on; null when absent
      - `utm_medium` string, nullable, required: The utm_medium of the page the session opened on; null when absent
      - `utm_campaign` string, nullable, required: The utm_campaign of the page the session opened on; null when absent
      - `utm_content` string, nullable, required: The utm_content of the page the session opened on; null when absent
      - `utm_term` string, nullable, required: The utm_term of the page the session opened on; null when absent
      - `answers` object, required: The session's answers keyed by component_key; a component on two pages holds its last answer. Email and phone answers only on endpoints with include_pii
      - `last_page` string, nullable, required: The page_key of the last page the shopper visited; null before any
      - `answered_count` integer, required: How many components answers holds
      - `source_session_id` string, nullable, required: The session this one was started from: a shared result (source_kind share) or a Restart (source_kind restart); null for a session the shopper opened themselves
      - `source_kind` string, nullable, required: share: started from a shared result | restart: started by Restart; null for a session the shopper opened themselves
      - `identities` ProfileIdentity[], nullable: Endpoints with include_pii only: the identities of the session's person
        - `kind` string, required: email | phone | shopify_customer_id. A new kind may be added, so skip one you do not know. shopify_customer_id arrives when the shopper takes a quiz logged in to the store or places an order linked to a quiz session; its consent is always false
        - `value` string, required: The email (lowercase), the phone (E.164), or the Shopify customer as a gid://shopify/Customer/<id> GID
        - `first_seen_at` string, date-time, nullable, required: When the identity was first captured
        - `last_seen_at` string, date-time, nullable, required: The latest moment one of the shopper's sessions typed this kind of contact, never earlier than first_seen_at
        - `consent` boolean, required: True only when the shopper ticked the marketing-consent box on their newest run that showed it; anything else, including a skipped page or a quiz without the box, is false
      - `completed_at` string, date-time, nullable, required: When the session completed; null on identity.captured before completion
      - `results_url` string, nullable, required: The link to this session's results once completed; null before
      - `formulas` ProfileFormula[], required: The formula values the quiz computed
        - `page_key` string, required: The page the formula or value table is on
        - `component_key` string, required: The formula or value table
        - `label` string, required: Its label
        - `value` number, nullable, required: The number it computed; null for a value table that holds text
        - `kind` 'formula' | 'table': A formula's number, or the value a value table resolved
        - `value_text` string, nullable: The text a value table resolved; null for a formula or a number table
      - `points` ProfilePoints[], required: The points per dimension the quiz computed
        - `dimension_id` string, required: The points dimension
        - `name` string, required: Its name
        - `total` number, required: The points the session scored on it
      - `terminal_page` ProfileResultPage, required
        - `page_key` string, required: The result page
        - `title` string, nullable, required: Its title; null when it has none
        - `position` integer, nullable, required: Its position in the quiz, from 1; null when not known
        - `page_count` integer, nullable, required: How many pages the quiz version has; null when not known
        - `shown_products` ProfileShownProduct[], required: The products it showed
          - `product_id` string, required: The product's Shopify GID
          - `variant_id` string, nullable, required: The variant's Shopify GID; null when the block showed the product only
          - `block_key` string, required: The product block that showed it
          - `handle` string, nullable, required: The product's handle; null when unknown
          - `title` string, nullable, required: The product's title; null when unknown
          - `variant_title` string, nullable, required: The variant's title; null when unknown
          - `price` number, nullable, required: The variant's price in the store's currency; null when unknown
          - `currency` string, nullable, required: The store's currency; null when unknown
          - `image` string, nullable, required: The product's image URL; null when unknown
      - `products_shown` WebhookProduct[], required: Every product the session showed; on quiz.finished those shown within a minute of completion
        - `product_id` string, required: The product's Shopify GID
        - `variant_id` string, nullable, required: The variant's Shopify GID; null when the block showed the product only
        - `block_key` string, required: The product block that showed it
        - `page_key` string, required: The page of that block
        - `position` integer, nullable, required: Its position in the block as shown; null when not recorded
        - `source` string, required: How the block picked it: manual | rankings | points | smart
        - `handle` string, nullable, required: The product's handle; null when unknown
        - `title` string, nullable, required: The product's title; null when unknown
        - `variant_title` string, nullable, required: The variant's title; null when unknown
        - `price` number, nullable, required: The variant's price in the store's currency; null when unknown
        - `currency` string, nullable, required: The store's currency; null when unknown
        - `image` string, nullable, required: The product's image URL; null when unknown
      - `property_mappings` WebhookPropertyMapping[], required: The quiz's enabled question-to-property mappings for integrations; contact questions only on endpoints with include_pii
        - `question_key` string, required: The question's component_key
        - `question_label` string, required: The question as the quiz labels it
        - `property_name` string, required: The profile property the answer is written to
        - `option_values` object, nullable, required: The value written for each option id; null when the answer is written as is

## Acknowledgement `200`

Any 2xx within 10 seconds acknowledges the event

## Other responses

- `4XX`: 410 ends the delivery and disables the endpoint; any other 4xx but 408 and 429 ends it
- `5XX`: Retried, as are 408, 429, a timeout and a network error: seven retries over about 28 hours, then the delivery is dead

---

[API](https://skmtc.dev/octaneai/apis/octane-ai-merchant-api.md) - [All operations](https://skmtc.dev/octaneai/apis/octane-ai-merchant-api/llms.txt) - [OpenAPI document](https://skmtc.dev/octaneai/apis/octane-ai-merchant-api/revisions/dc2d1aa2b7c6?raw)
