{"openapi":"3.1.0","info":{"title":"Voicepanel API","version":"1.5.0","termsOfService":"https://www.voicepanel.com/terms","license":{"name":"Proprietary","url":"https://www.voicepanel.com/terms"},"description":"API for creating and managing voice-based user research studies, distributing them to participants, and retrieving responses.\n\n## Authentication\n\nAll API requests require a Bearer token passed in the `Authorization` header.\n\n### Getting an API key\n\n1. Sign in to the [Voicepanel dashboard](https://app.voicepanel.co)\n2. Go to **Settings → API Tokens**\n3. Enter a name for the token (e.g. \"Production\" or \"CI/CD\") and click **Create**\n4. Copy the token immediately — it is only shown once\n\n### Making requests\n\nInclude your token in the `Authorization` header of every request:\n\n```bash\ncurl https://app.voicepanel.co/api/v1/studies \\\n  -H \"Authorization: Bearer vpt_your_token_here\" \\\n  -H \"Content-Type: application/json\"\n```\n\nIf the token is missing or invalid, the API returns a `401 Unauthorized` response.\n\n### Token scopes\n\nA token has full access unless you limit it when you create it. A token with the `stimuli:check_access` scope can call [GET /api/v1/stimuli/{stimulus_id}/access](#tag/stimuli/get-api-v1-stimuli-stimulus_id-access). A token with the `stimuli:claim` scope can call [POST /api/v1/stimuli/{stimulus_id}/claim](#tag/stimuli/post-api-v1-stimuli-stimulus_id-claim). A token the dashboard creates for stimulus access holds both scopes. Any other endpoint returns a `403 Forbidden` response to such a token. One such token works for every study in the account.\n\nA token belongs to one account. [GET /api/v1/account](#tag/account/get-api-v1-account) returns that account, and every create request defaults `account_id` to it. A request that names another account gets a `403 Forbidden` response.\n\n## Pagination\n\nEvery list endpoint returns `{ \"data\": [...], \"has_more\": false, \"next_cursor\": null }`. A list request returns one page. `limit` sets the page size (1-200) and defaults to 50. When `has_more` is true, pass `next_cursor` back as the `cursor` query parameter to read the next page, and repeat until `has_more` is false. Pages are ordered newest first, and a cursor is only valid for the filters it was issued with.\n\n## Errors\n\nEvery response with a status outside 2xx carries one JSON body, the `ApiError` envelope:\n\n```json\n{\n  \"error\": {\n    \"code\": \"validation_error\",\n    \"message\": \"Request validation failed\",\n    \"details\": { \"plan.sections[0].intro\": [\"Required\"] },\n    \"request_id\": \"iad1::abcde-1700000000000-0123456789ab\"\n  }\n}\n```\n\nThe HTTP status gives the class of failure. `code` is stable and is the field to branch on. `message` is for people and can change. `details` is optional and its shape depends on `code`. `request_id` identifies the request in our logs; quote it when you contact support.\n\nA query parameter the endpoint does not document is an error, not a no-op: the response is a 400 with `code` `validation_error` and the parameter name in `details`. So a filter typo such as `?study_id=` in place of `?studyId=` never returns every row.\n\nA method that a path does not document gets a 405 with `code` `method_not_allowed`. `details.allowed` and the `Allow` header list the methods that the path accepts.\n\n## Rate limits\n\nEach account can make 300 API requests in any 60-second window. All the tokens of an account share this limit, so a second token does not add capacity. Every request with a valid token counts, including a request that returns an error.\n\nEach response carries these headers:\n\n| Header | Value |\n| --- | --- |\n| `RateLimit-Limit` | The number of requests allowed in the window. |\n| `RateLimit-Remaining` | The number of requests left in the current window. |\n| `RateLimit-Reset` | The number of seconds until the window resets. |\n\nIf the account goes over the limit, the API returns a `429` response with `code` `too_many_requests` and a `Retry-After` header. Wait for the number of seconds in `Retry-After`, then send the request again. To stay under the limit, read `RateLimit-Remaining` and slow down before it reaches 0. Use `limit=200` on list endpoints to read more rows with fewer requests. If your integration needs a higher limit, contact support.\n\n## Parameter casing\n\nEach name has one spelling, and the API accepts that spelling only. Query parameters are camelCase (`studyId`, `distributionId`, `accountId`). Body fields and response fields are snake_case (`account_id`, `quota_limit`). The fields inside `plan` keep the spelling the plan reference documents. A query parameter in another spelling is a 400. A body field in another spelling is not read. Copy each name from the endpoint reference below.\n\nThe codes are: `bad_request`, `unauthorized`, `forbidden`, `not_found`, `method_not_allowed`, `conflict`, `already_member`, `too_many_requests`, `validation_error`, `internal_error`, `upstream_error`, `INVALID_CONDITIONAL_BRANCH`, `APP_ONLY_WEBSITE_DISTRIBUTION`, `FEATURE_FLAGS_UNAVAILABLE`, `STEP_TYPE_NOT_ENABLED`.\n\n## Getting Started\n\nThe Voicepanel API allows you to programmatically create voice-based research studies, distribute them to participants, and retrieve responses.\n\nAfter getting your API key, the typical flow is:\n\n1. **Create a study** — Use [POST /api/v1/studies](#tag/studies/post-api-v1-studies) to create a study and [PATCH /api/v1/studies/{study_id}](#tag/studies/patch-api-v1-studies-study_id) to configure your interview guide with sections, questions, and recording settings. Use [GET /api/v1/studies](#tag/studies/get-api-v1-studies) to list your studies or [GET /api/v1/studies/{study_id}](#tag/studies/get-api-v1-studies-study_id) to retrieve a specific one.\n2. **Set up distribution** — Use [POST /api/v1/distributions](#tag/distributions/post-api-v1-distributions) to define how you'd like to target the study — via a shareable link, panel provider, embedded widget, or other method. Use [GET /api/v1/distributions](#tag/distributions/get-api-v1-distributions) to list distributions or [GET /api/v1/distributions/{distribution_id}](#tag/distributions/get-api-v1-distributions-distribution_id) to retrieve a specific one.\n3. **Publish** — Use [POST /api/v1/distributions/{distribution_id}/publish](#tag/distributions/post-api-v1-distributions-distribution_id-publish) to make the distribution live and start collecting responses.\n4. **Fetch responses** — Use [GET /api/v1/responses](#tag/responses/get-api-v1-responses) to retrieve responses for your study, with filtering by distribution, status, date range, and more.\n5. **Pause or close** — Use [PATCH /api/v1/distributions/{distribution_id}/status](#tag/distributions/patch-api-v1-distributions-distribution_id-status) to pause, resume or complete the distribution.\n\n## Study and distribution lifecycle\n\nA study has no status of its own. It is live while at least one of its distributions is `published`, and it stops collecting responses when every distribution is `paused` or `completed`. So to pause a study, pause its distributions; to close a study, complete them.\n\nA distribution moves through these statuses: `draft` → `published` → `paused` → `published` (resume) → `completed`. [POST /api/v1/distributions/{distribution_id}/publish](#tag/distributions/post-api-v1-distributions-distribution_id-publish) is the only way out of `draft`. Every later change goes through [PATCH /api/v1/distributions/{distribution_id}/status](#tag/distributions/patch-api-v1-distributions-distribution_id-status). `completed` is final.\n\nStudies and distributions cannot be deleted. Archive one instead by setting `is_archived` to true with [PATCH /api/v1/studies/{study_id}](#tag/studies/patch-api-v1-studies-study_id) or [PATCH /api/v1/distributions/{distribution_id}](#tag/distributions/patch-api-v1-distributions-distribution_id). Archiving hides the row in the dashboard and keeps its responses. It does not change the status of a distribution, so complete a published distribution before you archive it.\n\n## Responses\n\nA **Response** is one participant's pass through a study. The full schema is under **Models** below. [GET /api/v1/responses](#tag/responses/get-api-v1-responses) returns the responses of a study with their transcripts, and [GET /api/v1/responses/{response_id}](#tag/responses/get-api-v1-responses-response_id) returns one.\n\n`status` tracks the participant's progress: `created` → `opened` → `in_progress` → `completed` or `incomplete`. `status_reason` says why a response ended. `mode` is the environment: `production` responses come from real participants, `preview` responses from the dashboard preview, and `simulation` responses from AI participants. The list endpoint returns production and simulation responses unless `environment=preview` is set.\n\nThe transcript is `messages`, an ordered list of **ResponseMessage** turns. Every message has the same shape: `role` says who spoke, `moderator` or `respondent`, and `content` says what was said as a **ResponseMessageContent**. Its `type` tells the shape of `value`: a `question` from the moderator, the transcript of a `spoken` answer, the text of an `open-text` answer, the choice of a `single_select`, the choices of a `multi_select`, the order of a `ranking`, or the row-to-column map of a matrix. A `task` adds a `completed` flag. Read selections from `content.value`; there is no separate text field to parse. `translated_messages` has the same `role` and `content`, with the English text as a `text` value at the same index. That value is always free text: a selection, a ranking or a matrix answer comes back in whatever wording the translation chose, so read typed answers from `messages`.\n\n## Webhooks\n\nRegister an HTTPS endpoint with [POST /api/v1/webhook_endpoints](#tag/webhooks/post-api-v1-webhook_endpoints) to receive a POST when a response completes (`response.completed`). Only production responses fire events; previews and simulations do not. The event body is listed under **Webhooks** below.\n\nEach request carries the [Standard Webhooks](https://www.standardwebhooks.com/) headers `webhook-id`, `webhook-timestamp` and `webhook-signature`, plus `x-voicepanel-event` with the event type. The signature is `v1,` followed by the base64 HMAC-SHA256 of `{webhook-id}.{webhook-timestamp}.{body}` keyed with the base64-decoded secret (strip the `whsec_` prefix). Any Standard Webhooks library verifies it with the secret from the create response. After a secret rotation, the header holds two space-separated signatures for 24 hours. Accept the request if any one of them matches.\n\nReturn a 2xx status within 10 seconds. Any other result is retried after 1m, 5m, 10m. An endpoint that returns 410 is disabled at once. An endpoint with no successful delivery for 7 days is disabled; re-enable it with [PATCH /api/v1/webhook_endpoints/{endpoint_id}](#tag/webhooks/patch-api-v1-webhook_endpoints-endpoint_id). Events are not ordered, and a retry repeats the same event ID, so make your handler idempotent.\n\n## Study plan reference\n\nThe `plan` field describes the whole interview: sections, question types, assets, recording modes, and logic. The [Study plan reference](https://www.voicepanel.com/docs/study-reference) documents every block with a JSON example, plus complete plans for common research methods.\n"},"servers":[{"url":"https://app.voicepanel.co","description":"Production"},{"url":"https://staging.voicepanel.co","description":"Staging. Open https://staging.voicepanel.co/api/docs to send requests here."}],"security":[{"bearerAuth":[]}],"paths":{"/api/v1/account":{"get":{"operationId":"getAccount","summary":"Get the account","description":"Retrieve the account the API token belongs to. Create requests default `account_id` to this account's `id`, so a client does not need to store it.","tags":["Account"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/v1/studies":{"get":{"operationId":"listStudies","summary":"List studies","description":"Retrieve the studies accessible to the authenticated account, newest first. Optionally filter by account ID. Returns one page of `limit` studies (default 50); pass `next_cursor` back as `cursor` to read the next page.","tags":["Studies"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudyListItem"}},"has_more":{"type":"boolean","description":"True when rows exist after the last one in data"},"next_cursor":{"type":["string","null"],"description":"Pass back as `cursor` to read the next page"}},"required":["data","has_more","next_cursor"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"accountId","in":"query","required":false,"schema":{"type":"string"},"description":"Filter studies by account ID"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Page size (1-200). Defaults to 50. When has_more is true, pass next_cursor back as cursor to read the next page."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's next_cursor. Returns the rows after that position."}]},"post":{"operationId":"createStudy","summary":"Create a study","description":"Create a new research study, with an optional plan configuration with sections, steps, and recording settings. The study belongs to the account of the API token unless `account_id` names it.","tags":["Studies"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Study"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyCreateBody"}}}}}},"/api/v1/studies/{study_id}":{"get":{"operationId":"getStudy","summary":"Get a study","description":"Retrieve a single study by its ID, including its full plan configuration.","tags":["Studies"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Study"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"study_id","in":"path","required":true,"description":"The study ID","schema":{"type":"string"}}]},"patch":{"operationId":"updateStudy","summary":"Update a study","description":"Update an existing study's configuration. The path names the study; the body carries only the fields to change. Any provided fields will be updated; omitted fields remain unchanged.","tags":["Studies"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Study"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"study_id","in":"path","required":true,"description":"The study ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyUpdateBody"}}}}}},"/api/v1/distributions":{"get":{"operationId":"listDistributions","summary":"List distributions","description":"Retrieve the distributions accessible to the authenticated account, newest first. Optionally filter by study ID or distribution type. Returns one page of `limit` distributions (default 50); pass `next_cursor` back as `cursor` to read the next page.","tags":["Distributions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Distribution"}},"has_more":{"type":"boolean","description":"True when rows exist after the last one in data"},"next_cursor":{"type":["string","null"],"description":"Pass back as `cursor` to read the next page"}},"required":["data","has_more","next_cursor"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"studyId","in":"query","required":false,"schema":{"type":"string"},"description":"Filter distributions by study ID"},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["link","service","email","website","app","panel","simulation"]},"description":"Filter by distribution type"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Page size (1-200). Defaults to 50. When has_more is true, pass next_cursor back as cursor to read the next page."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's next_cursor. Returns the rows after that position."}]},"post":{"operationId":"createDistribution","summary":"Create a distribution","description":"Create a new distribution for a study. A distribution defines how participants access the study — via a shareable link, a panel provider, embedded widget, or other method.","tags":["Distributions"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Distribution"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DistributionCreateBody"}}}}}},"/api/v1/distributions/{distribution_id}":{"get":{"operationId":"getDistribution","summary":"Get a distribution","description":"Retrieve a single distribution by its ID, including its full configuration. A link distribution carries its participant link in `url`.","tags":["Distributions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Distribution"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"distribution_id","in":"path","required":true,"description":"The distribution ID","schema":{"type":"string"}}]},"patch":{"operationId":"updateDistribution","summary":"Update a distribution","description":"Update an existing distribution's configuration. The path names the distribution; the body carries only the fields to change. Omitted fields remain unchanged. Set `is_archived` to archive or unarchive the distribution. `status` is not a field of this body: pause, resume or complete a distribution with [PATCH /api/v1/distributions/{distribution_id}/status](#tag/distributions/patch-api-v1-distributions-distribution_id-status), and make one live with [POST /api/v1/distributions/{distribution_id}/publish](#tag/distributions/post-api-v1-distributions-distribution_id-publish).","tags":["Distributions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Distribution"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"distribution_id","in":"path","required":true,"description":"The distribution ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DistributionUpdateBody"}}}}}},"/api/v1/distributions/{distribution_id}/publish":{"post":{"operationId":"publishDistribution","summary":"Publish a distribution","description":"Publish a distribution to make it live. For link/website distributions, this activates the distribution URL; a link distribution returns it in `url`. For panel distributions, this launches the project with the panel provider. Publish moves a `draft` or `in_review` distribution to `published`. To pause, resume or complete a distribution that is already published, use [PATCH /api/v1/distributions/{distribution_id}/status](#tag/distributions/patch-api-v1-distributions-distribution_id-status).","tags":["Distributions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The published distribution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Distribution"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"distribution_id","in":"path","required":true,"description":"The distribution ID to publish","schema":{"type":"string"}}]}},"/api/v1/distributions/{distribution_id}/status":{"patch":{"operationId":"updateDistributionStatus","summary":"Pause, resume or complete a distribution","description":"Change the status of a distribution that is already published. A study collects responses only while it has a `published` distribution, so this is how a study is paused or closed. `published` -> `paused` stops new participants from starting; `paused` -> `published` resumes; `published` or `paused` -> `completed` closes the distribution for good, and a completed panel distribution returns its unused credits. A `completed` distribution cannot change status again; duplicate it instead. `in_review` -> `draft` cancels a review request. Any other transition is a 409. A `draft` or `in_review` distribution goes live through the publish endpoint, which also charges credits and freezes the study snapshot. For a panel distribution, the provider project is paused, resumed or closed in the background after this call returns.","tags":["Distributions"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The distribution with its new status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Distribution"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"distribution_id","in":"path","required":true,"description":"The distribution ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DistributionStatusUpdateBody"}}}}}},"/api/v1/stimuli/{stimulus_id}/access":{"get":{"operationId":"checkStimulusAccess","summary":"Check stimulus access","description":"Check whether one response can see one stimulus. Use it on the server that hosts a prototype: admit a participant only while `allowed` is true. The check records nothing, so a participant can open the link again, and every call gives the same answer while the response is active. This makes a prototype link multi-use. For a single-use link, use [POST /api/v1/stimuli/{stimulus_id}/claim](#tag/stimuli/post-api-v1-stimuli-stimulus_id-claim) instead. When a participant opens a website, prototype, mobile app, or html stimulus, the URL carries both ids as query parameters: `voicepanel_response_id` and `voicepanel_stimulus_id`. Stimulus IDs also appear on each stimulus in a study's plan. A token with only the `stimuli:check_access` scope can call this endpoint.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusAccess"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}},{"name":"response_id","in":"query","required":true,"schema":{"type":"string"},"description":"The ID of the response that asks to see the stimulus"}]}},"/api/v1/stimuli/{stimulus_id}/claim":{"post":{"operationId":"claimStimulus","summary":"Claim a stimulus","description":"Claim one stimulus for one response. The first call for a response and a stimulus answers `allowed: true` and records the claim. Every later call for the same pair answers `allowed: false` with the reason `already_claimed`. This makes a prototype link single-use: a participant cannot reopen it, and a shared link admits nobody else. Use it on the server that hosts a prototype, and call it once, when the participant arrives. A page reload after the claim is refused, so keep the participant on the page, or use [GET /api/v1/stimuli/{stimulus_id}/access](#tag/stimuli/get-api-v1-stimuli-stimulus_id-access) for a multi-use link. A claim applies the rule of the access check first: the study plan must reference the stimulus and the response must be active. A refused claim records nothing. A preview response is always allowed and is never claimed, because the researcher replays it. When a participant opens a website, prototype, mobile app, or html stimulus, the URL carries both ids as query parameters: `voicepanel_response_id` and `voicepanel_stimulus_id`. A token with only the `stimuli:claim` scope can call this endpoint.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusClaim"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusClaimBody"}}}}}},"/api/v1/stimuli/{stimulus_id}/metadata":{"get":{"operationId":"getStimulusMetadata","summary":"Get stimulus metadata","description":"Retrieve the caller-defined attributes stored on a stimulus. Stimulus IDs appear on each stimulus in a study's plan.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadata"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}}]},"put":{"operationId":"replaceStimulusMetadata","summary":"Replace stimulus metadata","description":"Replace every attribute on a stimulus in one call. Values may be strings, numbers, booleans, or arrays of strings and numbers — a list may not hold booleans. Nested objects are flattened into dotted keys, so { \"pricing\": { \"tier\": \"pro\" } } is stored as { \"pricing.tier\": \"pro\" }. Null values are dropped.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadata"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadataReplaceBody"}}}}},"patch":{"operationId":"mergeStimulusMetadata","summary":"Merge stimulus metadata","description":"Merge attributes into a stimulus's existing metadata. Keys in the payload are replaced, keys left out are untouched. Nested objects are flattened the same way as a replace.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadata"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadataMergeBody"}}}}}},"/api/v1/stimuli/{stimulus_id}/metadata/{key}":{"get":{"operationId":"getStimulusMetadataAttribute","summary":"Get one metadata attribute","description":"Retrieve a single attribute from a stimulus's metadata. Returns 404 when the stimulus has no such key.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadataAttribute"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"The metadata key","schema":{"type":"string"}}]},"put":{"operationId":"setStimulusMetadataAttribute","summary":"Set one metadata attribute","description":"Set a single attribute, leaving the rest of the stimulus's metadata alone. An object value is flattened under the key and replaces anything already nested there; a null value removes the key.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadata"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"The metadata key","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadataKeyBody"}}}}},"delete":{"operationId":"deleteStimulusMetadataAttribute","summary":"Delete one metadata attribute","description":"Remove a single attribute from a stimulus's metadata, along with anything nested under it.","tags":["Stimuli"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StimulusMetadata"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"stimulus_id","in":"path","required":true,"description":"The stimulus ID","schema":{"type":"string"}},{"name":"key","in":"path","required":true,"description":"The metadata key","schema":{"type":"string"}}]}},"/api/v1/responses":{"get":{"operationId":"listResponses","summary":"List responses","description":"Retrieve responses for a study, transcripts included. Supports filtering by study, distribution, status, date range, and more. Without an `environment` filter, preview responses are left out. Returns one page of `limit` responses (default 50), ordered by creation time (newest first); pass `next_cursor` back as `cursor` to read the next page.","tags":["Responses"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Response"}},"has_more":{"type":"boolean","description":"True when rows exist after the last one in data"},"next_cursor":{"type":["string","null"],"description":"Pass back as `cursor` to read the next page"}},"required":["data","has_more","next_cursor"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"studyId","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by study ID"},{"name":"startDateTime","in":"query","required":false,"schema":{"type":"string"},"description":"Return responses created at or after this ISO 8601 datetime"},{"name":"endDateTime","in":"query","required":false,"schema":{"type":"string"},"description":"Return responses created at or before this ISO 8601 datetime"},{"name":"environment","in":"query","required":false,"schema":{"type":"string","enum":["production","preview"]},"description":"`production` (the default) returns production and simulation responses. `preview` returns preview responses only."},{"name":"hasMessages","in":"query","required":false,"schema":{"type":"string","enum":["true","false"]},"description":"`true` returns responses with at least one answer. `false` returns the rest."},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string","enum":["created","opened","incomplete","completed","in_progress"],"description":"Where the response is in its lifecycle. `created`: the link was opened but the welcome screen was not passed. `opened`: the respondent passed the welcome screen. `in_progress`: the respondent answered at least one question. `completed`: the interview finished. `incomplete`: the respondent left before the end, or was screened out."},{"type":"array","items":{"type":"string","enum":["created","opened","incomplete","completed","in_progress"],"description":"Where the response is in its lifecycle. `created`: the link was opened but the welcome screen was not passed. `opened`: the respondent passed the welcome screen. `in_progress`: the respondent answered at least one question. `completed`: the interview finished. `incomplete`: the respondent left before the end, or was screened out."}}]},"description":"Filter by response status. Repeat the parameter to match more than one status."},{"name":"distributionId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"description":"Filter by distribution ID. Repeat the parameter to match more than one distribution."},{"name":"id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"description":"Filter by response ID. Repeat the parameter to match more than one response."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Page size (1-200). Defaults to 50. When has_more is true, pass next_cursor back as cursor to read the next page."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's next_cursor. Returns the rows after that position."}]}},"/api/v1/responses/{response_id}":{"get":{"operationId":"getResponse","summary":"Get a response","description":"Retrieve a single response by its ID, with its full transcript in `messages`. A `response.completed` webhook event names the response; read the transcript here.","tags":["Responses"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Response"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"response_id","in":"path","required":true,"description":"The response ID","schema":{"type":"string"}}]}},"/api/v1/webhook_endpoints":{"get":{"operationId":"listWebhookEndpoints","summary":"List webhook endpoints","description":"Retrieve the webhook endpoints registered for the authenticated account.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}},"has_more":{"type":"boolean","description":"True when rows exist after the last one in data"},"next_cursor":{"type":["string","null"],"description":"Pass back as `cursor` to read the next page"}},"required":["data","has_more","next_cursor"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"accountId","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by account ID. A request with an API token defaults to the token's account."}]},"post":{"operationId":"createWebhookEndpoint","summary":"Create a webhook endpoint","description":"Register an HTTPS URL that receives a signed POST for each subscribed event. The response includes the signing secret once. Store it; it is not shown again.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"The endpoint, with its signing secret","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointWithSecret"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreateBody"}}}}}},"/api/v1/webhook_endpoints/{endpoint_id}":{"get":{"operationId":"getWebhookEndpoint","summary":"Get a webhook endpoint","description":"Retrieve a single webhook endpoint by its ID.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"endpoint_id","in":"path","required":true,"description":"The webhook endpoint ID","schema":{"type":"string"}}]},"patch":{"operationId":"updateWebhookEndpoint","summary":"Update a webhook endpoint","description":"Change the URL, description, or event types of an endpoint, or re-enable one that was disabled after repeated failures.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"endpoint_id","in":"path","required":true,"description":"The webhook endpoint ID","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointUpdateBody"}}}}},"delete":{"operationId":"deleteWebhookEndpoint","summary":"Delete a webhook endpoint","description":"Delete an endpoint and its delivery history. Pending deliveries are dropped.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointDeleted"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"endpoint_id","in":"path","required":true,"description":"The webhook endpoint ID","schema":{"type":"string"}}]}},"/api/v1/webhook_endpoints/{endpoint_id}/rotate_secret":{"post":{"operationId":"rotateWebhookEndpointSecret","summary":"Rotate a webhook secret","description":"Generate a new signing secret for the endpoint. For 24 hours, each delivery carries two signatures in `webhook-signature`: one from the new secret and one from the previous secret. Deploy the new secret to your verifier before `previous_secret_expires_at`. After that time, deliveries carry only the new signature.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecretRotation"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"endpoint_id","in":"path","required":true,"description":"The webhook endpoint ID","schema":{"type":"string"}}]}},"/api/v1/webhook_endpoints/{endpoint_id}/test":{"post":{"operationId":"testWebhookEndpoint","summary":"Send a test event","description":"Queue a `webhook.test` event to the endpoint. It is signed and retried like a real event, so use it to check your verifier.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"The queued test delivery","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"endpoint_id","in":"path","required":true,"description":"The webhook endpoint ID","schema":{"type":"string"}}]}},"/api/v1/webhook_endpoints/{endpoint_id}/deliveries":{"get":{"operationId":"listWebhookDeliveries","summary":"List webhook deliveries","description":"Retrieve recent deliveries for an endpoint, newest first, with the HTTP status and response body of the last attempt. Deliveries are kept for 30 days.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}},"has_more":{"type":"boolean","description":"True when rows exist after the last one in data"},"next_cursor":{"type":["string","null"],"description":"Pass back as `cursor` to read the next page"}},"required":["data","has_more","next_cursor"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"}},"parameters":[{"name":"endpoint_id","in":"path","required":true,"description":"The webhook endpoint ID","schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","succeeded","failed"]},"description":"Filter by delivery status"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Maximum rows to return (default 50)"},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque cursor from a previous page's next_cursor. Returns the rows after that position."}]}},"/api/v1/webhook_endpoints/{endpoint_id}/deliveries/{delivery_id}/retry":{"post":{"operationId":"retryWebhookDelivery","summary":"Retry a webhook delivery","description":"Queue a finished delivery again with the same event ID and payload. The retry schedule starts over.","tags":["Webhooks"],"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"The delivery, queued again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"endpoint_id","in":"path","required":true,"description":"The webhook endpoint ID","schema":{"type":"string"}},{"name":"delivery_id","in":"path","required":true,"description":"The webhook delivery ID","schema":{"type":"string"}}]}}},"webhooks":{"response.completed":{"post":{"operationId":"responseCompletedWebhook","summary":"response.completed","description":"A participant completed a response","tags":["Webhooks"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","created_at","data"],"properties":{"id":{"type":"string","description":"Event ID. Retries of the same event reuse it, so dedupe on it."},"type":{"type":"string","enum":["response.completed"]},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"response":{"$ref":"#/components/schemas/WebhookEventResponse"}}}}}}}},"responses":{"2XX":{"description":"Return any 2xx status within 10 seconds to acknowledge the event."}}}}},"components":{"schemas":{"Json":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/components/schemas/Json"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"}}]},"ApiError":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["bad_request","unauthorized","forbidden","not_found","method_not_allowed","conflict","already_member","too_many_requests","validation_error","internal_error","upstream_error","INVALID_CONDITIONAL_BRANCH","APP_ONLY_WEBSITE_DISTRIBUTION","FEATURE_FLAGS_UNAVAILABLE","STEP_TYPE_NOT_ENABLED"],"description":"Stable, machine-readable error code. Branch on this field, not on `message`."},"message":{"type":"string","description":"Human-readable explanation. The text can change."},"details":{"description":"Extra context whose shape depends on `code`. A `validation_error` maps each invalid field path to its messages. A `method_not_allowed` lists the allowed methods.","$ref":"#/components/schemas/Json"},"request_id":{"description":"Id of this request in the platform logs. Quote it when you contact support.","type":"string"}},"required":["code","message"]}},"required":["error"],"description":"The error envelope every non-2xx response carries."},"Account":{"type":"object","properties":{"id":{"type":"string","description":"Account ID. Create requests made with an API token default `account_id` to it."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Account name"},"panel_credits_in_cents":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Panel credits available, in US cents"}},"required":["id","name","panel_credits_in_cents"],"description":"The account an API token belongs to"},"StudyPlan":{"type":"object","properties":{"version":{"type":"string"},"sections":{"type":"array","items":{"type":"object","properties":{"intro":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"steps":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"task"},"task_type":{"type":"string","enum":["visit_website","download_app","open_app","watch_video","generic_instruction"]},"expected_duration_seconds":{"type":"number"}},"required":["question","type","task_type"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"long_question"},"probing_areas":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"probing_type":{"default":"light","type":"string","enum":["none","light","custom"]},"response_format":{"default":"audio","type":"string","enum":["audio","audio_only","chat_only","chat"]}},"required":["question","type"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"single_select"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"shuffle_options":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"vertically_align_choices":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["question","type","options"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"multi_select"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"shuffle_options":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"vertically_align_choices":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["question","type","options"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"rating_scale"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"lowest_rating_label":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"highest_rating_label":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["question","type","options"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"ranking"},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"shuffle_options":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["question","type","options"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"matrix_single_select"},"rows":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"columns":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"shuffle_options":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["question","type","rows","columns"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"matrix_multi_select"},"rows":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"columns":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"anchor":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]},"exclusive":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["value"]}},"shuffle_options":{"default":null,"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["question","type","rows","columns"]},{"type":"object","properties":{"question":{"type":"string"},"type":{"type":"string","const":"conversation"},"time_limit_seconds":{"type":"number"},"conversation_mode":{"type":"string","enum":["no-guide","guide"]},"conversation_guide":{"default":null,"anyOf":[{"type":"string"},{"type":"null"}]},"response_format":{"default":"audio","type":"string","enum":["audio","audio_only","chat_only","chat"]}},"required":["question","type","time_limit_seconds","conversation_mode"]}]}},"stimulus":{"anyOf":[{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","const":"text"},"content":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}]}},"placement":{"anyOf":[{"type":"string","enum":["throughout","at-start"]},{"type":"null"}]},"displaySeconds":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]}},"required":["type","content"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["website","mobile_app","audio","video","youtube","prototype","image","html","offline","none"]},"url":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}]}},"urlPreview":{"anyOf":[{"type":"object","properties":{"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"favicon":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"botProtected":{"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["image","title","description"]},{"type":"null"}]},"placement":{"anyOf":[{"type":"string","enum":["throughout","at-start"]},{"type":"null"}]},"displaySeconds":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]},"sizing":{"anyOf":[{"type":"string","enum":["fit","fit-width","fit-height"]},{"type":"null"}]}},"required":["type","url"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","const":"group"},"stimuli":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","const":"text"},"content":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}]}},"placement":{"anyOf":[{"type":"string","enum":["throughout","at-start"]},{"type":"null"}]},"displaySeconds":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]}},"required":["type","content"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["website","mobile_app","audio","video","youtube","prototype","image","html","offline","none"]},"url":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}]}},"urlPreview":{"anyOf":[{"type":"object","properties":{"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"favicon":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"botProtected":{"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["image","title","description"]},{"type":"null"}]},"placement":{"anyOf":[{"type":"string","enum":["throughout","at-start"]},{"type":"null"}]},"displaySeconds":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]},"sizing":{"anyOf":[{"type":"string","enum":["fit","fit-width","fit-height"]},{"type":"null"}]}},"required":["type","url"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","const":"side_by_side"},"stimuli":{"maxItems":4,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["image","html"]},"url":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}]}},"urlPreview":{"anyOf":[{"type":"object","properties":{"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"favicon":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"botProtected":{"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["image","title","description"]},{"type":"null"}]},"placement":{"anyOf":[{"type":"string","enum":["throughout","at-start"]},{"type":"null"}]},"displaySeconds":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]},"sizing":{"anyOf":[{"type":"string","enum":["fit","fit-width","fit-height"]},{"type":"null"}]}},"required":["type","url"]}},"displaySeconds":{"anyOf":[{"type":"number"},{"type":"null"}]},"sizing":{"anyOf":[{"type":"string","enum":["fit","fit-width","fit-height"]},{"type":"null"}]}},"required":["type","stimuli"]}]}},"showCount":{"type":"number"},"displaySeconds":{"anyOf":[{"type":"number"},{"type":"null"}]},"sizing":{"anyOf":[{"type":"string","enum":["fit","fit-width","fit-height"]},{"type":"null"}]}},"required":["type","stimuli","showCount"]},{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","const":"side_by_side"},"stimuli":{"maxItems":4,"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["image","html"]},"url":{"type":"string"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"label":{"anyOf":[{"type":"string"},{"type":"null"}]},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}]}},"urlPreview":{"anyOf":[{"type":"object","properties":{"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"title":{"anyOf":[{"type":"string"},{"type":"null"}]},"description":{"anyOf":[{"type":"string"},{"type":"null"}]},"favicon":{"anyOf":[{"type":"string"},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"botProtected":{"anyOf":[{"type":"boolean"},{"type":"null"}]}},"required":["image","title","description"]},{"type":"null"}]},"placement":{"anyOf":[{"type":"string","enum":["throughout","at-start"]},{"type":"null"}]},"displaySeconds":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}]},"sizing":{"anyOf":[{"type":"string","enum":["fit","fit-width","fit-height"]},{"type":"null"}]}},"required":["type","url"]}},"displaySeconds":{"anyOf":[{"type":"number"},{"type":"null"}]},"sizing":{"anyOf":[{"type":"string","enum":["fit","fit-width","fit-height"]},{"type":"null"}]}},"required":["type","stimuli"]}]},{"type":"null"}]},"recording":{"anyOf":[{"type":"object","properties":{"audio":{"default":false,"type":"boolean"},"video":{"default":false,"type":"boolean"},"screen":{"default":false,"type":"boolean"},"mobile_screen":{"default":false,"type":"boolean"}}},{"type":"null"}]},"conditionalBranch":{"anyOf":[{"anyOf":[{"type":"object","properties":{"sourceType":{"type":"string","const":"segment"},"segmentationKey":{"type":"string"},"triggerValues":{"type":"array","items":{"type":"string"}}},"required":["sourceType","segmentationKey","triggerValues"]},{"type":"object","properties":{"sourceType":{"type":"string","const":"task"},"sourceSectionIndex":{"type":"number"},"sourceStepIndex":{"type":"number"},"triggerValues":{"type":"array","items":{"type":"string","enum":["completed","not_completed"]}}},"required":["sourceType","sourceSectionIndex","sourceStepIndex","triggerValues"]},{"type":"object","properties":{"sourceType":{"type":"string","const":"question"},"sourceSectionIndex":{"type":"number"},"sourceStepIndex":{"type":"number"},"triggerValues":{"type":"array","items":{"type":"string"}}},"required":["sourceSectionIndex","sourceStepIndex","triggerValues"]}]},{"type":"null"}]}},"required":["steps"]}},"randomizations":{"type":"array","items":{"type":"object","properties":{"sectionIndices":{"type":"array","items":{"type":"number"}}},"required":["sectionIndices"]}},"flagged_content":{"type":"boolean"},"device":{"type":"string","enum":["any","desktop","mobile","ios","android"]}},"required":["version","sections","randomizations"]},"Tag":{"type":"object","properties":{"id":{"type":"string","description":"Tag ID"},"account_id":{"type":"string","description":"Account that owns the tag"},"name":{"type":"string","description":"Tag name"},"created_at":{"type":"string","format":"date-time"}},"required":["id","account_id","name","created_at"],"description":"A tag attached to a study"},"Study":{"type":"object","properties":{"id":{"type":"string","description":"Study ID"},"account_id":{"type":"string","description":"Account that owns the study"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Public-facing study name shown to participants"},"internal_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Internal name for organization purposes"},"objective":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Research objective for the study"},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Brand or product context for the AI interviewer"},"plan":{"anyOf":[{"$ref":"#/components/schemas/StudyPlan"},{"type":"null"}],"description":"Study plan with sections, steps, and recording config. Stimuli are returned inline. Every block, with examples: https://www.voicepanel.com/docs/study-reference"},"plan_source":{"type":"string","enum":["study.questions","study.plan"],"description":"Field that holds the interview content. Studies created through the API use `study.plan`."},"questions":{"description":"Legacy question list, used only when plan_source is `study.questions`","$ref":"#/components/schemas/Json"},"brand_logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL of brand logo shown during the interview"},"brand_words":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Brand-related keywords for AI interviewer context"},"brand_words_generated":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Brand keywords the AI derived from the study context"},"show_welcome_page":{"type":"boolean","description":"Whether to show a welcome page before starting"},"welcome_text":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Custom welcome page text"},"target_length_min":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target interview length in minutes"},"uniqueness_constraint":{"anyOf":[{"type":"string","enum":["custom_id_required","custom_id_required_single_submission"]},{"type":"null"}],"description":"Enforce unique responses via custom ID"},"written_in_language":{"type":"string","description":"Language code the study is written in"},"is_archived":{"type":"boolean","description":"Whether the study is archived"},"is_pre_draft":{"type":"boolean","description":"True while an AI-authored study is still being assembled. List endpoints leave these studies out."},"enable_tts_default":{"type":"boolean","description":"Whether text-to-speech is enabled by default"},"tts_voice_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Voice ID for text-to-speech"},"screen_out_criteria":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Criteria the AI interviewer uses to screen out a participant"},"template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Template the study was created from"},"authoring_method":{"type":"string","enum":["scratch","ai_chat","template"],"description":"How the study was authored"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Client that created the study: `web`, `api`, or `mcp`"},"last_edited_source":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Client that last edited the study"},"last_modified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the study content last changed"},"demo_report":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Generated demo report, if one exists"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the user who created the study"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"tags":{"type":"array","items":{"$ref":"#/components/schemas/Tag"},"description":"Tags attached to the study"}},"required":["id","account_id","display_name","internal_name","objective","context","plan","plan_source","questions","brand_logo_url","brand_words","brand_words_generated","show_welcome_page","welcome_text","target_length_min","uniqueness_constraint","written_in_language","is_archived","is_pre_draft","enable_tts_default","tts_voice_id","screen_out_criteria","template_id","authoring_method","source","last_edited_source","last_modified_at","demo_report","created_by","created_at","updated_at","tags"],"description":"A research study"},"StudyListItem":{"type":"object","properties":{"id":{"type":"string","description":"Study ID"},"account_id":{"type":"string","description":"Account that owns the study"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Public-facing study name shown to participants"},"internal_name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Internal name for organization purposes"},"objective":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Research objective for the study"},"context":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Brand or product context for the AI interviewer"},"plan":{"anyOf":[{"$ref":"#/components/schemas/StudyPlan"},{"type":"null"}],"description":"Study plan with sections, steps, and recording config. Stimuli are returned inline. Every block, with examples: https://www.voicepanel.com/docs/study-reference"},"plan_source":{"type":"string","enum":["study.questions","study.plan"],"description":"Field that holds the interview content. Studies created through the API use `study.plan`."},"questions":{"description":"Legacy question list, used only when plan_source is `study.questions`","$ref":"#/components/schemas/Json"},"brand_logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL of brand logo shown during the interview"},"brand_words":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Brand-related keywords for AI interviewer context"},"brand_words_generated":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Brand keywords the AI derived from the study context"},"show_welcome_page":{"type":"boolean","description":"Whether to show a welcome page before starting"},"welcome_text":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Custom welcome page text"},"target_length_min":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Target interview length in minutes"},"uniqueness_constraint":{"anyOf":[{"type":"string","enum":["custom_id_required","custom_id_required_single_submission"]},{"type":"null"}],"description":"Enforce unique responses via custom ID"},"written_in_language":{"type":"string","description":"Language code the study is written in"},"is_archived":{"type":"boolean","description":"Whether the study is archived"},"is_pre_draft":{"type":"boolean","description":"True while an AI-authored study is still being assembled. List endpoints leave these studies out."},"enable_tts_default":{"type":"boolean","description":"Whether text-to-speech is enabled by default"},"tts_voice_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Voice ID for text-to-speech"},"screen_out_criteria":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Criteria the AI interviewer uses to screen out a participant"},"template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Template the study was created from"},"authoring_method":{"type":"string","enum":["scratch","ai_chat","template"],"description":"How the study was authored"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Client that created the study: `web`, `api`, or `mcp`"},"last_edited_source":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Client that last edited the study"},"last_modified_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the study content last changed"},"demo_report":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Generated demo report, if one exists"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the user who created the study"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"tags":{"type":"array","items":{"$ref":"#/components/schemas/Tag"},"description":"Tags attached to the study"},"distribution_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Distributions that are published, paused, or completed"},"in_review_distribution_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Distributions that wait for a review before publish"},"computed_status":{"type":"string","enum":["completed","paused","collecting","draft"],"description":"Status derived from the study's distributions and responses"},"created_by_user":{"anyOf":[{"type":"object","properties":{"id":{"type":"string","description":"User ID"},"first_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"last_name":{"anyOf":[{"type":"string"},{"type":"null"}]},"is_support":{"type":"boolean","description":"True when the creator is a Voicepanel support login"}},"required":["id","first_name","last_name","is_support"],"description":"The user who created the study"},{"type":"null"}]}},"required":["id","account_id","display_name","internal_name","objective","context","plan","plan_source","questions","brand_logo_url","brand_words","brand_words_generated","show_welcome_page","welcome_text","target_length_min","uniqueness_constraint","written_in_language","is_archived","is_pre_draft","enable_tts_default","tts_voice_id","screen_out_criteria","template_id","authoring_method","source","last_edited_source","last_modified_at","demo_report","created_by","created_at","updated_at","tags","distribution_count","in_review_distribution_count","computed_status","created_by_user"],"description":"A study as returned by the list endpoint, with its counts"},"StudyCreateBody":{"type":"object","properties":{"account_id":{"description":"ID of the account to create the study under. Defaults to the account of the API token.","type":"string"},"display_name":{"description":"Public-facing study name shown to participants","default":"Brief Voice Survey","anyOf":[{"type":"string"},{"type":"null"}]},"internal_name":{"description":"Internal name for organization purposes","anyOf":[{"type":"string"},{"type":"null"}]},"objective":{"description":"Research objective for the study","anyOf":[{"type":"string"},{"type":"null"}]},"context":{"description":"Brand or product context for the AI interviewer","anyOf":[{"type":"string"},{"type":"null"}]},"plan":{"description":"Study plan with sections, steps, and recording config. Every block, with examples: https://www.voicepanel.com/docs/study-reference","anyOf":[{"$ref":"#/components/schemas/StudyPlan"},{"type":"null"}]},"brand_logo_url":{"description":"URL of brand logo shown during the interview","anyOf":[{"type":"string"},{"type":"null"}]},"show_welcome_page":{"description":"Whether to show a welcome page before starting","default":true,"type":"boolean"},"target_length_min":{"description":"Target interview length in minutes","default":5,"anyOf":[{"type":"number"},{"type":"null"}]},"welcome_text":{"description":"Custom welcome page text","anyOf":[{"type":"string"},{"type":"null"}]},"written_in_language":{"description":"Language code the study is written in","default":"en-US","type":"string"},"is_archived":{"description":"Whether the study is archived","default":false,"type":"boolean"},"brand_words":{"description":"Brand-related keywords for AI interviewer context","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"enable_tts_default":{"description":"Whether text-to-speech is enabled by default","default":false,"type":"boolean"},"tts_voice_id":{"description":"Voice ID for text-to-speech","anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"description":"Tags for organizing studies","type":"array","items":{"type":"string"}}}},"StudyUpdateBody":{"type":"object","properties":{"display_name":{"description":"Public-facing study name","anyOf":[{"type":"string"},{"type":"null"}]},"internal_name":{"description":"Internal name","anyOf":[{"type":"string"},{"type":"null"}]},"objective":{"description":"Research objective","anyOf":[{"type":"string"},{"type":"null"}]},"context":{"description":"Brand or product context","anyOf":[{"type":"string"},{"type":"null"}]},"plan":{"description":"Study plan configuration. Every block, with examples: https://www.voicepanel.com/docs/study-reference","anyOf":[{"$ref":"#/components/schemas/StudyPlan"},{"type":"null"}]},"brand_logo_url":{"description":"URL of brand logo","anyOf":[{"type":"string"},{"type":"null"}]},"show_welcome_page":{"description":"Show welcome page","type":"boolean"},"target_length_min":{"description":"Target length in minutes","anyOf":[{"type":"number"},{"type":"null"}]},"welcome_text":{"description":"Welcome page text","anyOf":[{"type":"string"},{"type":"null"}]},"written_in_language":{"description":"Language code","type":"string"},"is_archived":{"description":"Whether archived","type":"boolean"},"brand_words":{"description":"Brand-related keywords","anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"enable_tts_default":{"description":"Whether text-to-speech is enabled by default","type":"boolean"},"tts_voice_id":{"description":"Voice ID for TTS","anyOf":[{"type":"string"},{"type":"null"}]},"tags":{"description":"Tags","type":"array","items":{"type":"string"}}}},"Distribution":{"type":"object","properties":{"id":{"type":"string","description":"Distribution ID"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Public link participants open to take the study. Set for link distributions only; null for every other type."},"study_id":{"type":"string","description":"ID of the study this distribution belongs to"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Name of the distribution"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Description of the distribution"},"type":{"type":"string","enum":["link","service","email","website","app","panel","simulation"],"description":"How the study is distributed to participants"},"status":{"type":"string","enum":["draft","published","paused","completed","in_review"],"description":"Current status of the distribution"},"distribution_provider":{"anyOf":[{"type":"string","enum":["respondent","user_interviews","prolific","terac"],"description":"Third-party panel provider"},{"type":"null"}]},"distribution_provider_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"External provider project ID"},"config":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"},"description":"Provider-specific configuration"},"incentive":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"}},{"type":"null"}],"description":"Incentive configuration for link distributions"},"quota_limit":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Maximum number of responses"},"quota_frequency":{"type":"string","enum":["lifetime","monthly","weekly","daily"],"description":"How often the quota resets"},"quota_usage":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Responses counted against the current quota"},"segment_quotas":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Per-segment subquotas within the overall quota"},"screener_questions":{"type":"array","items":{"$ref":"#/components/schemas/Json"},"description":"Screener questions for qualifying participants"},"targeting_condition":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Targeting rules for who is eligible"},"device_targeting":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Device requirements frozen from the study plan at publish"},"default_response_language":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Default language for responses"},"collect_email":{"type":"boolean","description":"Whether to collect participant email"},"screen_email":{"type":"boolean","description":"Whether to screen participants against an email list"},"email_list_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Email list used to screen or invite participants"},"automatic_invites":{"type":"boolean","description":"Whether participants are invited automatically"},"key":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Snippet key used to trigger an intercept distribution"},"traffic_threshold":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Share of eligible traffic shown the study, out of 1,000,000"},"complete_redirect_url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL to redirect to after completion"},"screen_out_redirect_url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL to redirect screened-out participants"},"quota_full_redirect_url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL to redirect when quota is full"},"quality_terminate_redirect_url":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"URL to redirect participants terminated for quality"},"study_data":{"description":"Snapshot of the study taken at publish. Participants see this version, not later edits to the study.","$ref":"#/components/schemas/Json"},"is_archived":{"type":"boolean","description":"Whether the distribution is archived"},"seq_num":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Sequence number within the study"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the distribution was published"},"last_completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the latest response completed"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the user who created the distribution"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"pretranslations":{"description":"Locales with a stored translation of the distribution. Not returned by publish.","type":"array","items":{"type":"object","properties":{"locale":{"type":"string"}},"required":["locale"]}}},"required":["id","url","study_id","name","description","type","status","distribution_provider","distribution_provider_id","config","incentive","quota_limit","quota_frequency","quota_usage","segment_quotas","screener_questions","targeting_condition","device_targeting","default_response_language","collect_email","screen_email","email_list_id","automatic_invites","key","traffic_threshold","complete_redirect_url","screen_out_redirect_url","quota_full_redirect_url","quality_terminate_redirect_url","study_data","is_archived","seq_num","published_at","last_completed_at","created_by","created_at","updated_at"],"description":"A distribution of a study to participants"},"DistributionCreateBody":{"type":"object","properties":{"study_id":{"type":"string","description":"ID of the study this distribution belongs to"},"name":{"description":"Name of the distribution","anyOf":[{"type":"string"},{"type":"null"}]},"type":{"default":"link","type":"string","enum":["link","service","email","website","app","panel","simulation"],"description":"How the study is distributed to participants"},"distribution_provider":{"anyOf":[{"type":"string","enum":["respondent","user_interviews","prolific","terac"],"description":"Third-party panel provider"},{"type":"null"}]},"config":{"description":"Provider-specific configuration","default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"}},"incentive":{"description":"Incentive configuration for link distributions","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"}},{"type":"null"}]},"quota_limit":{"description":"Maximum number of responses","default":10,"anyOf":[{"type":"number"},{"type":"null"}]},"quota_frequency":{"description":"How often the quota resets","default":"lifetime","type":"string","enum":["lifetime","monthly","weekly","daily"]},"segment_quotas":{"description":"Per-segment subquotas within the overall quota","anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}]},"screener_questions":{"description":"Screener questions for qualifying participants","default":[],"type":"array","items":{"$ref":"#/components/schemas/Json"}},"targeting_condition":{"description":"Targeting rules for who is eligible","anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}]},"default_response_language":{"description":"Default language for responses","anyOf":[{"type":"string"},{"type":"null"}]},"collect_email":{"description":"Whether to collect participant email","default":false,"type":"boolean"},"screen_email":{"description":"Whether to screen participants against an email list","default":false,"type":"boolean"},"email_list_id":{"description":"Email list used to screen or invite participants","anyOf":[{"type":"string"},{"type":"null"}]},"automatic_invites":{"description":"Whether participants are invited automatically","default":true,"type":"boolean"},"key":{"description":"Snippet key used to trigger an intercept distribution","anyOf":[{"type":"string"},{"type":"null"}]},"traffic_threshold":{"description":"Share of eligible traffic shown the study, out of 1,000,000","anyOf":[{"type":"number"},{"type":"null"}]},"complete_redirect_url":{"description":"URL to redirect to after completion","anyOf":[{"type":"string"},{"type":"null"}]},"screen_out_redirect_url":{"description":"URL to redirect screened-out participants","anyOf":[{"type":"string"},{"type":"null"}]},"quota_full_redirect_url":{"description":"URL to redirect when quota is full","anyOf":[{"type":"string"},{"type":"null"}]},"quality_terminate_redirect_url":{"description":"URL to redirect participants terminated for quality","anyOf":[{"type":"string"},{"type":"null"}]},"description":{"description":"Description of the distribution","anyOf":[{"type":"string"},{"type":"null"}]},"is_archived":{"description":"Whether the distribution is archived. Archiving hides it in the dashboard and does not change its status.","default":false,"type":"boolean"}},"required":["study_id"]},"DistributionUpdateBody":{"type":"object","properties":{"name":{"description":"Name of the distribution","anyOf":[{"type":"string"},{"type":"null"}]},"type":{"type":"string","enum":["link","service","email","website","app","panel","simulation"],"description":"How the study is distributed to participants"},"distribution_provider":{"anyOf":[{"type":"string","enum":["respondent","user_interviews","prolific","terac"],"description":"Third-party panel provider"},{"type":"null"}]},"config":{"description":"Provider-specific configuration","type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"}},"incentive":{"description":"Incentive configuration for link distributions","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"}},{"type":"null"}]},"quota_limit":{"description":"Maximum number of responses","anyOf":[{"type":"number"},{"type":"null"}]},"quota_frequency":{"description":"How often the quota resets","type":"string","enum":["lifetime","monthly","weekly","daily"]},"segment_quotas":{"description":"Per-segment subquotas within the overall quota","anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}]},"screener_questions":{"description":"Screener questions for qualifying participants","type":"array","items":{"$ref":"#/components/schemas/Json"}},"targeting_condition":{"description":"Targeting rules for who is eligible","anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}]},"default_response_language":{"description":"Default language for responses","anyOf":[{"type":"string"},{"type":"null"}]},"collect_email":{"description":"Whether to collect participant email","type":"boolean"},"screen_email":{"description":"Whether to screen participants against an email list","type":"boolean"},"email_list_id":{"description":"Email list used to screen or invite participants","anyOf":[{"type":"string"},{"type":"null"}]},"automatic_invites":{"description":"Whether participants are invited automatically","type":"boolean"},"key":{"description":"Snippet key used to trigger an intercept distribution","anyOf":[{"type":"string"},{"type":"null"}]},"traffic_threshold":{"description":"Share of eligible traffic shown the study, out of 1,000,000","anyOf":[{"type":"number"},{"type":"null"}]},"complete_redirect_url":{"description":"URL to redirect to after completion","anyOf":[{"type":"string"},{"type":"null"}]},"screen_out_redirect_url":{"description":"URL to redirect screened-out participants","anyOf":[{"type":"string"},{"type":"null"}]},"quota_full_redirect_url":{"description":"URL to redirect when quota is full","anyOf":[{"type":"string"},{"type":"null"}]},"quality_terminate_redirect_url":{"description":"URL to redirect participants terminated for quality","anyOf":[{"type":"string"},{"type":"null"}]},"description":{"description":"Description of the distribution","anyOf":[{"type":"string"},{"type":"null"}]},"is_archived":{"description":"Whether the distribution is archived. Archiving hides it in the dashboard and does not change its status.","type":"boolean"}}},"DistributionStatusUpdateBody":{"type":"object","properties":{"status":{"type":"string","enum":["published","paused","completed","draft"],"description":"The status to move to. `paused` stops a published distribution from taking new participants. `published` resumes a paused one. `completed` closes a published or paused one for good and, for a panel distribution, returns unused credits. `draft` cancels a review request on an `in_review` distribution. A draft or in_review distribution goes live through the publish endpoint, not through this one."}},"required":["status"],"description":"Change the status of a distribution"},"Response":{"type":"object","properties":{"id":{"type":"string","description":"Response ID"},"study_id":{"type":"string","description":"ID of the study"},"distribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the distribution the participant came through. Null for a preview."},"segment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the segment the participant was recruited for"},"status":{"type":"string","enum":["created","opened","incomplete","completed","in_progress"],"description":"Where the response is in its lifecycle. `created`: the link was opened but the welcome screen was not passed. `opened`: the respondent passed the welcome screen. `in_progress`: the respondent answered at least one question. `completed`: the interview finished. `incomplete`: the respondent left before the end, or was screened out."},"status_reason":{"anyOf":[{"type":"string","enum":["exited_welcome_screen","exited_paused_screen","started_interview","screened_out","interview_error","spam","hit_time_limit","answered_all_questions","content_filter","inactive_timeout","recording_stopped","quota_full"],"description":"Why the response has its status. `answered_all_questions` and `hit_time_limit` go with `completed`. `exited_welcome_screen`, `exited_paused_screen`, `screened_out`, `quota_full`, `inactive_timeout`, `recording_stopped`, `interview_error`, `content_filter` and `spam` go with `incomplete`. `started_interview` goes with `in_progress`."},{"type":"null"}]},"mode":{"type":"string","enum":["preview","production","simulation"],"description":"The environment the response was collected in. `production` responses come from real participants. `preview` responses come from the dashboard preview. `simulation` responses come from AI simulated participants. Previews and simulations do not count toward quotas, and only `production` responses fire webhooks."},"format":{"type":"string","enum":["video","audio","chat","audio_only","chat_only"],"description":"How the respondent answered the open-ended questions. `video` records the camera. `audio` and `audio_only` record the voice. `chat` and `chat_only` are typed. An `_only` value means the study offered no other input."},"language":{"type":"string","description":"ISO 639-1 code of the language the participant took the interview in"},"custom_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own participant ID, read from the `cid` query parameter of the study link"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Participant email, when collected"},"query_params":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Every query parameter of the link the participant opened, including panel participant IDs"},"messages":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ResponseMessage"}},{"type":"null"}],"description":"The transcript, in order. Null until the participant answers the first question. Left out of webhook events."},"translated_messages":{"anyOf":[{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["moderator","respondent"],"description":"Who spoke: the AI moderator or the respondent."},"content":{"type":"object","properties":{"type":{"type":"string","const":"text","description":"The content of every translated message."},"value":{"type":"string","description":"The message translated into English. Always free text, whatever the type of the answer. A selection, a ranking or a matrix answer comes back in whatever wording the translation chose, such as `Red, Blue`, so read the typed answer from `messages` at the same index."}},"required":["type","value"]}},"required":["role","content"],"description":"One turn of `messages`, translated into English. It is at the same index as the message it translates."}},{"type":"null"}],"description":"`messages` translated into English, one entry per message at the same index. Null when the interview was in English."},"screener_responses":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"The participant's answers to the screener of the distribution. Null when the distribution has no screener."},"translated_screener_responses":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"`screener_responses` translated into English. Null when the screener was in English."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"AI-generated summary of the response, when one was made"},"seconds_elapsed":{"type":"number","description":"Seconds the participant spent in the interview"},"quality_score":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"The AI quality rating of the response: `{ overallRating, reason }`. An `overallRating` of `low` or `very-low` flags the response in the dashboard."},"moderator_quality_score":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Reserved. Null today."},"segments":{"description":"The value of each segmentation of the study for this response, keyed by the segmentation key: `{ value, error }`","$ref":"#/components/schemas/Json"},"include_in_analysis":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"Whether the response counts in analysis. A completed response is included unless a reviewer rejects it."},"has_messages":{"anyOf":[{"type":"boolean"},{"type":"null"}],"description":"True when the participant answered at least one question"},"has_evaluated_screen_out":{"type":"boolean","description":"Whether the screen-out criteria were evaluated"},"additional_info":{"description":"Profile and demographic data from the panel provider, when the participant came from a panel. An empty object otherwise.","$ref":"#/components/schemas/Json"},"device_info":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"The device the participant used, read from the user agent: `{ device, browser, os, userAgent }`. Null for responses collected before this field existed."},"call_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the phone call, for phone interviews"},"call_provider":{"anyOf":[{"type":"string","enum":["vapi","retell"]},{"type":"null"}],"description":"Provider of the phone call"},"feedback":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"The thumbs up or down the participant left on the end screen, with their comment: `{ vote, textInput }`"},"message_media_expected":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Per-answer recordings the plan asks for"},"message_media_completed":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Per-answer recordings that were uploaded"},"section_media_expected":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Section recordings (screen, camera) the plan asks for"},"section_media_completed":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"Section recordings that were uploaded"},"panel_incentive_amount":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Incentive the participant was recruited at, in whole USD. Panel distributions only."},"panel_recruiting_fee":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Recruiting fee at recruitment, in whole USD. Panel distributions only."},"seq_num":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The response number shown in the dashboard. It counts up from 1 within the study."},"opened_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the participant passed the welcome screen"},"first_message_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the participant answered the first question"},"last_message_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the transcript last changed"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the link was opened"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the response last changed"}},"required":["id","study_id","distribution_id","segment_id","status","status_reason","mode","format","language","custom_id","email","query_params","messages","translated_messages","screener_responses","translated_screener_responses","summary","seconds_elapsed","quality_score","moderator_quality_score","segments","include_in_analysis","has_messages","has_evaluated_screen_out","additional_info","device_info","call_id","call_provider","feedback","message_media_expected","message_media_completed","section_media_expected","section_media_completed","panel_incentive_amount","panel_recruiting_fee","seq_num","opened_at","first_message_at","last_message_at","created_at","updated_at"],"description":"One participant's pass through a study: who they are, how far they got, and the transcript of what was asked and answered."},"ResponseMessage":{"type":"object","properties":{"role":{"type":"string","enum":["moderator","respondent"],"description":"Who spoke: the AI moderator or the respondent."},"content":{"$ref":"#/components/schemas/ResponseMessageContent"},"sectionNumber":{"description":"1-based position of the section in the plan, as authored.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"stepNumber":{"description":"1-based position of the step inside its section.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"probeNumber":{"description":"1 for the scripted question and its answer. 2 and up for each follow-up probe the AI moderator asked on the same step.","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"secondsElapsed":{"description":"Seconds from the start of the interview to the end of this message.","type":"number"},"sectionId":{"description":"ID of the section run the message belongs to. It is the `sectionNumber`, plus a letter when the section loops over a group of stimuli: `2` for section 2, `2b` for the run that shows the second stimulus of the group, in the authored order. It does not change when sections or stimuli are randomized.","type":"string"}},"required":["role","content"],"description":"One turn of the interview. Messages alternate between the moderator's question and the respondent's answer, in the order they happened. Sections appear in the order the respondent saw them, which differs from `sectionNumber` when sections are randomized."},"ResponseMessageContent":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"question","description":"The content of every `moderator` message."},"value":{"type":"string","description":"The question or follow-up probe the AI moderator asked, as the respondent saw or heard it."}},"required":["type","value"],"description":"What the AI moderator said. Only on a `moderator` message."},{"type":"object","properties":{"type":{"type":"string","const":"spoken","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"string","description":"The transcript of what the respondent said. Empty when no transcript was produced."}},"required":["type","value"],"description":"A spoken answer to an open-ended step."},{"type":"object","properties":{"type":{"type":"string","const":"open-text","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"string","description":"The text the respondent typed."}},"required":["type","value"],"description":"A typed answer to an open-ended step."},{"type":"object","properties":{"type":{"type":"string","const":"single_select","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"string","description":"The selected choice."}},"required":["type","value"],"description":"A single-select step."},{"type":"object","properties":{"type":{"type":"string","const":"multi_select","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"array","items":{"type":"string"},"description":"The selected choices."}},"required":["type","value"],"description":"A multi-select step."},{"type":"object","properties":{"type":{"type":"string","const":"rating_scale","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"string","description":"The selected rating, as a string."}},"required":["type","value"],"description":"A rating-scale step."},{"type":"object","properties":{"type":{"type":"string","const":"ranking","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"array","items":{"type":"string"},"description":"The choices in the respondent's order, first to last."}},"required":["type","value"],"description":"A ranking step."},{"type":"object","properties":{"type":{"type":"string","const":"matrix_single_select","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"string"},"description":"The selected column, keyed by row text."}},"required":["type","value"],"description":"A matrix step with one selection per row."},{"type":"object","properties":{"type":{"type":"string","const":"matrix_multi_select","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"type":"array","items":{"type":"string"}},"description":"The selected columns, keyed by row text."}},"required":["type","value"],"description":"A matrix step with several selections per row."},{"type":"object","properties":{"type":{"type":"string","const":"task","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"completed":{"type":"boolean","description":"Whether the respondent completed the task."},"value":{"type":"string","description":"What the respondent said aloud while on the task. Empty when they said nothing."}},"required":["type","completed","value"],"description":"A task step."},{"type":"object","properties":{"type":{"type":"string","const":"spoken_raw_audio","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"string","description":"The transcript. Empty when no transcript was produced."}},"required":["type","value"],"description":"A spoken answer whose audio went to the moderator without a transcript."},{"type":"object","properties":{"type":{"type":"string","const":"detected","description":"The kind of answer. It matches the step type for a closed-choice step, and names the input method for an open-ended step."},"value":{"type":"string","description":"The part of the earlier answer that answers this question."},"referenceIndexes":{"type":"array","items":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"description":"Indexes into `messages` of the answers the moderator read this from."}},"required":["type","value","referenceIndexes"],"description":"An answer the AI moderator found inside the respondent's answer to a different question."}],"description":"What a message says. `type` tells which shape `value` has. A `moderator` message always holds a `question`. A `respondent` message holds one of the answer shapes."},"StimulusAccess":{"type":"object","properties":{"allowed":{"type":"boolean","description":"True if the response can see the stimulus. The study plan must reference the stimulus and the response must be active. A response is active while its status is `opened` or `in_progress` and its distribution is `published`. A paused or completed distribution closes the study, so its responses are inactive. A preview response is always active, because it is the researcher's own test run. A participant who leaves stays active until the response times out, which can take up to about 15 minutes."},"reason":{"anyOf":[{"type":"string","enum":["response_inactive","stimulus_not_in_study"]},{"type":"null"}],"description":"Why access is refused. `stimulus_not_in_study`: the plan of the response's study does not reference the stimulus. `response_inactive`: the response is completed, incomplete, or not yet opened, or its distribution is paused or completed. A preview response never gets this reason. Null when `allowed` is true."}},"required":["allowed","reason"],"description":"Whether one response can see one stimulus"},"StimulusClaim":{"type":"object","properties":{"allowed":{"type":"boolean","description":"True if this call claimed the stimulus for the response. The study plan must reference the stimulus and the response must be active. A response is active while its status is `opened` or `in_progress` and its distribution is `published`. A paused or completed distribution closes the study, so its responses are inactive. A preview response is always active, because it is the researcher's own test run. A participant who leaves stays active until the response times out, which can take up to about 15 minutes. The first call that passes this rule records the claim. Every later call for the same response and stimulus is refused. A preview response is always allowed and is never claimed."},"reason":{"anyOf":[{"type":"string","enum":["response_inactive","stimulus_not_in_study","already_claimed"]},{"type":"null"}],"description":"Why the claim is refused. `stimulus_not_in_study`: the plan of the response's study does not reference the stimulus. `response_inactive`: the response is completed, incomplete, or not yet opened, or its distribution is paused or completed. A preview response never gets this reason. `already_claimed`: an earlier call claimed the stimulus for this response. Null when `allowed` is true."}},"required":["allowed","reason"],"description":"Whether one response claimed one stimulus"},"StimulusClaimBody":{"type":"object","properties":{"response_id":{"type":"string","description":"The ID of the response that asks to see the stimulus"}},"required":["response_id"],"description":"Claim a stimulus for a response"},"StimulusMetadata":{"type":"object","properties":{"id":{"type":"string","description":"The stimulus ID"},"study_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the study the stimulus belongs to"},"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}]},"description":"Flat attributes. A key maps to a string, a number, a boolean, or a list of strings and numbers."}},"required":["id","study_id","metadata"],"description":"A stimulus with its metadata"},"StimulusMetadataAttribute":{"type":"object","properties":{"key":{"type":"string","description":"The metadata key"},"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"number"}]}}],"description":"The stored value"}},"required":["key","value"],"description":"One metadata attribute of a stimulus"},"StimulusMetadataReplaceBody":{"type":"object","properties":{"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Attributes to store on the stimulus. Values may be strings, numbers, booleans, or arrays of strings and numbers — a list may not hold booleans. Nested objects are flattened into dotted keys — { \"pricing\": { \"tier\": \"pro\" } } is stored as { \"pricing.tier\": \"pro\" }. Null values are dropped."}},"required":["metadata"],"description":"Replace a stimulus's metadata"},"StimulusMetadataMergeBody":{"type":"object","properties":{"metadata":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"Attributes to store on the stimulus. Values may be strings, numbers, booleans, or arrays of strings and numbers — a list may not hold booleans. Nested objects are flattened into dotted keys — { \"pricing\": { \"tier\": \"pro\" } } is stored as { \"pricing.tier\": \"pro\" }. Null values are dropped."}},"required":["metadata"],"description":"Merge attributes into a stimulus's metadata"},"StimulusMetadataKeyBody":{"type":"object","properties":{"value":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"array","items":{}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}],"description":"The value to store — a string, a number, a boolean, or an array of strings and numbers. An object is flattened under the key, replacing anything already nested there. Null removes the key."}},"required":["value"],"description":"Set a single metadata key on a stimulus"},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string","description":"The webhook endpoint ID"},"account_id":{"type":"string","description":"The account that owns the endpoint"},"url":{"type":"string","description":"HTTPS URL that receives a POST for each event"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A label shown in the dashboard"},"event_types":{"type":"array","items":{"type":"string","enum":["response.completed"]},"description":"Event types the endpoint receives"},"enabled":{"type":"boolean","description":"False when deliveries are stopped, by you or after failures"},"disabled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the endpoint was disabled"},"disabled_reason":{"anyOf":[{"type":"string","enum":["endpoint_returned_410","failing_for_7_days","manual"]},{"type":"null"}],"description":"Why the endpoint was disabled"},"consecutive_failures":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Failed deliveries since the last success"},"last_success_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"last_failure_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"previous_secret_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"After a rotation, when deliveries stop carrying the previous signature"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the user who created the endpoint"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","account_id","url","description","event_types","enabled","disabled_at","disabled_reason","consecutive_failures","last_success_at","last_failure_at","previous_secret_expires_at","created_by","created_at","updated_at"],"description":"A webhook endpoint"},"WebhookEndpointWithSecret":{"type":"object","properties":{"id":{"type":"string","description":"The webhook endpoint ID"},"account_id":{"type":"string","description":"The account that owns the endpoint"},"url":{"type":"string","description":"HTTPS URL that receives a POST for each event"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"A label shown in the dashboard"},"event_types":{"type":"array","items":{"type":"string","enum":["response.completed"]},"description":"Event types the endpoint receives"},"enabled":{"type":"boolean","description":"False when deliveries are stopped, by you or after failures"},"disabled_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the endpoint was disabled"},"disabled_reason":{"anyOf":[{"type":"string","enum":["endpoint_returned_410","failing_for_7_days","manual"]},{"type":"null"}],"description":"Why the endpoint was disabled"},"consecutive_failures":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Failed deliveries since the last success"},"last_success_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"last_failure_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"previous_secret_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"After a rotation, when deliveries stop carrying the previous signature"},"created_by":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the user who created the endpoint"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"secret":{"type":"string","description":"Signing secret, prefixed `whsec_`. Shown once; store it to verify deliveries."},"warning":{"type":"string","description":"Reminder that the secret is not shown again"}},"required":["id","account_id","url","description","event_types","enabled","disabled_at","disabled_reason","consecutive_failures","last_success_at","last_failure_at","previous_secret_expires_at","created_by","created_at","updated_at","secret","warning"],"description":"A new webhook endpoint with its signing secret"},"WebhookEndpointDeleted":{"type":"object","properties":{"success":{"type":"boolean","const":true},"id":{"type":"string","description":"ID of the deleted endpoint"}},"required":["success","id"],"description":"Confirmation that an endpoint was deleted"},"WebhookEndpointCreateBody":{"type":"object","properties":{"account_id":{"description":"The account that owns the endpoint. Defaults to the account of the API token.","type":"string"},"url":{"type":"string","format":"uri","description":"HTTPS URL that receives a POST for each event. Private and loopback addresses are rejected."},"description":{"description":"A label shown in the dashboard","type":"string","maxLength":200},"event_types":{"minItems":1,"type":"array","items":{"type":"string","enum":["response.completed"]},"description":"Event types the endpoint receives. `response.completed` fires when a participant completes a response."}},"required":["url","event_types"],"description":"Create a webhook endpoint"},"WebhookEndpointUpdateBody":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"HTTPS URL that receives a POST for each event. Private and loopback addresses are rejected."},"description":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}]},"event_types":{"minItems":1,"type":"array","items":{"type":"string","enum":["response.completed"]},"description":"Event types the endpoint receives. `response.completed` fires when a participant completes a response."},"enabled":{"description":"Set to false to stop deliveries; the endpoint records `disabled_reason: manual`. Set to true to re-enable an endpoint, including one that was disabled after repeated failures.","type":"boolean"}},"description":"Update a webhook endpoint"},"WebhookSecretRotation":{"type":"object","properties":{"id":{"type":"string","description":"The webhook endpoint ID"},"secret":{"type":"string","description":"Signing secret, prefixed `whsec_`. Shown once; store it to verify deliveries."},"previous_secret_expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When deliveries stop carrying the previous signature"},"warning":{"type":"string","description":"Reminder that the secret is not shown again"}},"required":["id","secret","previous_secret_expires_at","warning"],"description":"The result of a secret rotation"},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","description":"The webhook delivery ID"},"endpoint_id":{"type":"string","description":"The webhook endpoint ID"},"account_id":{"type":"string","description":"The account that owns the endpoint"},"event_id":{"type":"string","description":"Event ID sent in the `webhook-id` header"},"event_type":{"type":"string","enum":["response.completed","webhook.test"],"description":"Event type sent in the `x-voicepanel-event` header"},"payload":{"type":"object","properties":{"id":{"type":"string","description":"Event ID. Retries of the same event reuse it."},"type":{"type":"string","description":"Event type"},"created_at":{"type":"string","format":"date-time"},"data":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/components/schemas/Json"},"description":"Event data. Listed per event type under Webhooks."}},"required":["id","type","created_at","data"],"description":"The event body as delivered to the endpoint"},"status":{"type":"string","enum":["pending","succeeded","failed"],"description":"`pending` while attempts remain"},"attempts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Attempts made so far"},"last_attempt_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"response_status":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"HTTP status of the last attempt"},"response_body":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Response body of the last attempt, truncated"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Error of the last attempt, when no response arrived"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}},"required":["id","endpoint_id","account_id","event_id","event_type","payload","status","attempts","last_attempt_at","response_status","response_body","error","created_at","updated_at"],"description":"One delivery of an event to an endpoint"},"WebhookEventResponse":{"type":"object","properties":{"id":{"type":"string","description":"Response ID"},"study_id":{"type":"string","description":"ID of the study"},"distribution_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the distribution the participant came through. Null for a preview."},"segment_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"ID of the segment the participant was recruited for"},"status":{"type":"string","enum":["created","opened","incomplete","completed","in_progress"],"description":"Where the response is in its lifecycle. `created`: the link was opened but the welcome screen was not passed. `opened`: the respondent passed the welcome screen. `in_progress`: the respondent answered at least one question. `completed`: the interview finished. `incomplete`: the respondent left before the end, or was screened out."},"status_reason":{"anyOf":[{"type":"string","enum":["exited_welcome_screen","exited_paused_screen","started_interview","screened_out","interview_error","spam","hit_time_limit","answered_all_questions","content_filter","inactive_timeout","recording_stopped","quota_full"],"description":"Why the response has its status. `answered_all_questions` and `hit_time_limit` go with `completed`. `exited_welcome_screen`, `exited_paused_screen`, `screened_out`, `quota_full`, `inactive_timeout`, `recording_stopped`, `interview_error`, `content_filter` and `spam` go with `incomplete`. `started_interview` goes with `in_progress`."},{"type":"null"}]},"mode":{"type":"string","enum":["preview","production","simulation"],"description":"The environment the response was collected in. `production` responses come from real participants. `preview` responses come from the dashboard preview. `simulation` responses come from AI simulated participants. Previews and simulations do not count toward quotas, and only `production` responses fire webhooks."},"format":{"type":"string","enum":["video","audio","chat","audio_only","chat_only"],"description":"How the respondent answered the open-ended questions. `video` records the camera. `audio` and `audio_only` record the voice. `chat` and `chat_only` are typed. An `_only` value means the study offered no other input."},"language":{"type":"string","description":"ISO 639-1 code of the language the participant took the interview in"},"custom_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Your own participant ID, read from the `cid` query parameter of the study link"},"query_params":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"Every query parameter of the link the participant opened, including panel participant IDs"},"seconds_elapsed":{"type":"number","description":"Seconds the participant spent in the interview"},"quality_score":{"anyOf":[{"$ref":"#/components/schemas/Json"},{"type":"null"}],"description":"The AI quality rating of the response: `{ overallRating, reason }`. An `overallRating` of `low` or `very-low` flags the response in the dashboard."},"seq_num":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"The response number shown in the dashboard. It counts up from 1 within the study."},"opened_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the participant passed the welcome screen"},"first_message_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the participant answered the first question"},"last_message_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the transcript last changed"},"created_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the link was opened"},"updated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"description":"When the response last changed"}},"required":["id","study_id","distribution_id","segment_id","status","status_reason","mode","format","language","custom_id","query_params","seconds_elapsed","quality_score","seq_num","opened_at","first_message_at","last_message_at","created_at","updated_at"],"description":"The response without its transcript. Read the transcript with GET /api/v1/responses/{response_id}."}},"responses":{"BadRequest":{"description":"Bad request. `code` is `validation_error` when a field is invalid or a query parameter is unknown, with the field paths in `details`, or `bad_request` otherwise.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Unauthorized":{"description":"Unauthorized. The token is missing, invalid, or has no user.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Forbidden":{"description":"Forbidden. The token has no access to this resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"NotFound":{"description":"Not found. The resource does not exist or belongs to another account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"Conflict":{"description":"Conflict. The write disagrees with the current state of the resource.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"TooManyRequests":{"description":"Too many requests. The account used its API rate limit. `code` is `too_many_requests`. Wait for the number of seconds in `Retry-After`, then retry.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"InternalError":{"description":"Internal error. Quote `request_id` when you contact support.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"ServiceUnavailable":{"description":"Service unavailable. A dependency did not answer and nothing was saved. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API token from the Voicepanel dashboard (Settings → API Tokens)"}}}}