API reference
Generated from the schemas the API validates against, so a field listed here is a field the API accepts.
OpenAPI 3.1: https://api.50heads.com/openapi.json. Generated from the same schemas, so it never drifts from this page. Load it into Postman, Insomnia or a client generator.
Pricing and config
Unauthenticated and rate limited. Estimate as often as you like; it never spends.
POST/v1/billing/estimate
Price, time and validation for a question draft.
No authentication.
Counts as half a request against the rate limit. validation lists anything that would stop the ask, one issue per field.
| Field | Type | Notes |
|---|---|---|
draft | object | required |
draft. | "single_choice" | | required |
draft. | string | required up to 600 characters |
draft. | string | up to 120 characters |
draft. | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
draft. | object[] | up to 8 items, default [] |
draft. | string | required up to 40 characters |
draft. | string (URL) | |
draft. | string (URL)[] | up to 4 items |
draft. | object | |
draft. | string | required up to 24 characters |
draft. | string | required up to 24 characters |
draft. | boolean | default false |
draft. | object | |
draft. | string (URL) | |
draft. | string (URL) | |
draft. | string | up to 120 characters |
draft. | integer | 2000–10000 |
draft. | integer | 10–5000, default 50 |
draft. | 1 | | default 1 |
draft. | boolean | default false |
draft. | object | |
draft. | string[] | up to 50 items, default [] |
draft. | string[] | up to 20 items, default [] |
draft. | "18-24" | | up to 6 items |
draft. | "woman" | | up to 3 items |
draft. | boolean | |
draft. | object | |
draft. | integer | 1–5, default 1 |
draft. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
draft. | boolean | default false |
draft. | "off" | | default "off" |
draft. | object | |
draft. | number | required 0.5–0.95 |
draft. | integer | required 5–5000 |
draft. | "none" | | |
draft. | string | up to 40 characters |
draft. | 1 | | |
draft. | object | |
draft. | integer | required 1–10000 |
draft. | integer | required 0–10000 |
draft. | "heads" | | default "heads" |
draft. | 1 | | default 7 |
draft. | string | up to 40 characters |
surface | "app" | |
| Field | Type | Notes |
|---|---|---|
creditsPerAnswer | integer | required |
creditsTotal | integer | required |
payPerAnswer | integer | required |
etaMinutes | integer | required |
traits | integer | required |
breakdown | object[] | required |
breakdown[] | string | required |
breakdown[] | string | required |
breakdownLine | string | required |
validation | object[] | required |
validation[] | string | required |
validation[] | string | required |
validation[] | string | required |
poolSize | integer | | required |
GET/v1/config
Credit exchange rates, the country table and question languages.
No authentication.
| Field | Type | Notes |
|---|---|---|
rates | map of number | required |
ratesDate | string | required |
countries | map of object | required |
defaultCountry | object | required |
defaultCountry. | integer | required |
defaultCountry. | string[] | required |
defaultCountry. | "sms" | | required |
defaultCountry. | string[] | required |
defaultCountry. | boolean | required |
defaultCountry. | "GBP" | | required |
defaultCountry. | "GBP" | | |
defaultCountry. | object[] | |
defaultCountry. | string | required |
defaultCountry. | string | required |
defaultCountry. | string | |
defaultCountry. | string | |
defaultCountry. | "card" | | |
defaultCountry. | string | |
defaultCountry. | string[] | |
defaultCountry. | "uk" | | |
defaultCountry. | string | up to 40 characters |
defaultCountry. | string | up to 40 characters |
defaultCountry. | integer | 13–21 |
defaultCountry. | "known" | | |
questionLanguages | "en" | | required |
reverifyDays | integer | required |
tier1PayPence | integer | required |
tier2PayMultiplier | number | required |
answeringCountries | string[] | |
tremendous | "off" | | |
webTopUpStorefronts | string[] | |
storeCreditPacks | object[] | |
storeCreditPacks[] | string | required |
storeCreditPacks[] | integer | required |
POST/v1/estimate
A quick price and time from a tier, a number of heads and images.
No authentication.
Never spends. Defaults: tier1, 50 heads, no images. For a real question (targeting, question type, validation) send a draft to POST /v1/billing/estimate; this route also accepts that body when it has a draft. Counts against the same rate limit.
| Field | Type | Notes |
|---|---|---|
tier | "tier1" | | default "tier1" |
n | integer | 10–5000, default 50 |
images | integer | 0–4, default 0 |
| Field | Type | Notes |
|---|---|---|
estimate | object | required |
estimate. | "tier1" | | required |
estimate. | integer | required |
estimate. | integer | required |
estimate. | integer | required |
estimate. | integer | required |
estimate. | integer | required |
estimate. | integer | required |
line | string | required |
creditsPerAnswer | integer | required |
creditsTotal | integer | required |
payPerAnswer | integer | required |
etaMinutes | integer | required |
price | object | required |
poolSize | integer | | required |
validation | object[] | required |
validation[] | string | required |
validation[] | string | required |
validation[] | string | required |
GET/v1/config/platform
Whether asking through MCP is paused, the minimum app versions and the feature flags.
No authentication.
Read by the MCP server before it asks. Safe to cache for a minute.
| Field | Type | Notes |
|---|---|---|
killSwitch | object | required |
killSwitch. | boolean | required |
killSwitch. | boolean | required |
killSwitch. | string | | required |
killSwitch. | string | | required |
appVersions | object | required |
appVersions. | string | required |
appVersions. | string | required |
mcp | object | required |
mcp. | boolean | required |
mcp. | string[] | required |
mcp. | string | | required |
mcp. | string | | required |
flags | map of object | required |
GET/v1/templates
Fixed-price question templates.
No authentication.
| Field | Type | Notes |
|---|---|---|
templates | object[] | required |
templates[] | string | required |
templates[] | string | required |
templates[] | string | required |
templates[] | object | required |
templates[] | "single_choice" | | required |
templates[] | string | required up to 600 characters |
templates[] | string | up to 120 characters |
templates[] | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
templates[] | object[] | required up to 8 items, default [] |
templates[] | object | |
templates[] | boolean | required default false |
templates[] | object | |
templates[] | integer | required 10–5000, default 50 |
templates[] | 1 | | required default 1 |
templates[] | boolean | required default false |
templates[] | object | |
templates[] | object | |
templates[] | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
templates[] | boolean | required default false |
templates[] | "off" | | required default "off" |
templates[] | object | |
templates[] | "none" | | |
templates[] | string | up to 40 characters |
templates[] | 1 | | |
templates[] | object | |
templates[] | "heads" | | required default "heads" |
templates[] | 1 | | required default 7 |
templates[] | string | up to 40 characters |
templates[] | integer | required |
GET/v1/public/countries
Where heads answer from, the languages they read and pool size bands by tier.
No authentication.
| Field | Type | Notes |
|---|---|---|
countries | object[] | required |
countries[] | string | required up to 2 characters, at least 2 characters |
countries[] | string | required |
countries[] | string[] | required |
countries[] | boolean | required |
countries[] | object | required |
countries[] | string | | required |
countries[] | string | | required |
countries[] | string | | required |
updatedAt | string | required |
GET/v1/tags
The self-declared tags you can target at any tier, by group (one trait per group).
No authentication.
| Field | Type | Notes |
|---|---|---|
groups | object[] | required |
groups[] | "life_stage" | | required |
groups[] | string | required |
groups[] | string | required |
groups[] | integer | required |
tags | object[] | required |
tags[] | string | required |
tags[] | "life_stage" | | required |
tags[] | string | required |
GET/v1/public/stats
Heads online now, answers this week and the median time to fifty answers.
No authentication.
| Field | Type | Notes |
|---|---|---|
headsOnlineNow | integer | required |
answersThisWeek | integer | required |
medianMinutesTo50 | number | required |
headEarningsPerHour | object | required |
headEarningsPerHour. | integer | required |
headEarningsPerHour. | integer | required |
updatedAt | string | required |
GET/v1/public/subprocessors
Upcoming and past changes to our subprocessors, with their effective dates.
No authentication.
Cacheable for an hour. We email every account holder before adding or changing a subprocessor, and give at least 30 days' notice (noticeDays). upcoming holds announced changes that have not taken effect, soonest first; history holds the rest, newest first. Drafts are never listed. The current list itself is on the subprocessors page.
| Field | Type | Notes |
|---|---|---|
upcoming | object[] | required |
upcoming[] | string | required |
upcoming[] | "add" | | required |
upcoming[] | string | required |
upcoming[] | string | required |
upcoming[] | string | required |
upcoming[] | string | required |
upcoming[] | string | required |
upcoming[] | string | | required |
upcoming[] | "announced" | | required |
upcoming[] | string | required |
upcoming[] | string | required |
upcoming[] | string | | required |
history | object[] | required |
history[] | string | required |
history[] | "add" | | required |
history[] | string | required |
history[] | string | required |
history[] | string | required |
history[] | string | required |
history[] | string | required |
history[] | string | | required |
history[] | "announced" | | required |
history[] | string | required |
history[] | string | required |
history[] | string | | required |
noticeDays | integer | required |
updatedAt | string | required |
Status, identity and limits
Read these before you spend: whether 50heads is working and asking is open, who your key or grant acts as, and the rate limits on it. Every response that counts against a limit carries RateLimit-Policy, RateLimit, RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers; a 429 also carries Retry-After.
GET/v1/status
Whether 50heads is working, and whether asking, answering, MCP asking or top-ups are paused.
No authentication.
Cached for 15 seconds. 503 with the same body when the database is not answering. An agent should not ask while asking or mcp_asking is paused; nothing is charged while paused.
| Field | Type | Notes |
|---|---|---|
status | "operational" | | required |
components | object[] | required |
components[] | "api" | | required |
components[] | "operational" | | required |
components[] | string | | required |
message | string | | required |
until | string | | required |
checkedAt | string | required |
page | string | required |
GET/v1/whoami
Who this credential is, its scopes, its connection's caps and spend, and the account and organization it acts in.
API key or OAuth token.
Any key, connected app, service account or signed-in person; no scope needed. organization is null unless organizations are switched on for the team (and, for keys and apps, machine identities too).
| Field | Type | Notes |
|---|---|---|
principal | object | required |
principal. | "person" | | required |
principal. | string | required |
principal. | string | | required |
auth | "session" | | required |
scopes | string[] | | required |
connection | object | | required |
connection. | string | required |
connection. | "oauth" | | required |
connection. | string | | required |
connection. | string | required |
connection. | string | | required |
connection. | "questions:read" | | required |
connection. | integer | required |
connection. | integer | required |
connection. | integer | required |
connection. | string | | required |
connection. | boolean | | required |
connection. | string | required |
connection. | string | | required |
connection. | integer | | |
connection. | integer | | |
connection. | string | | |
account | object | required |
account. | "personal" | | required |
account. | string | | required |
account. | string | | required |
account. | "owner" | | required |
organization | object | | required |
organization. | string | required |
organization. | string | required |
organization. | boolean | required |
GET/v1/limits
The rate limits on this account and connection, with what is used in the current window.
API key or OAuth token.
Any credential; no scope needed. Counts are approximate (a brake on runaway loops, not a quota). The MCP server's own limits are listed with used: null.
| Field | Type | Notes |
|---|---|---|
policies | object[] | required |
policies[] | string | required |
policies[] | string | required |
policies[] | "account" | | required |
policies[] | integer | required |
policies[] | integer | required |
policies[] | integer | | required |
policies[] | integer | | required |
policies[] | integer | required |
note | string | required |
Questions
Ask, wait and read results. Asking reserves the full price from your credits; answers not given are refunded when the question closes.
POST/v2/questions
Ask a question.
API key or OAuth token with questions:write. Idempotency-Key header required.
Requires an Idempotency-Key header (a UUID). The same key returns the same question for 24 hours; a different body with the same key is idempotency_conflict. Fails with insufficient_credits, spend_cap_reached or content_refused without spending anything. The portal and app are reminded once with 422 quality_reminder (nothing stored or charged) when the wording review has a strong suggestion the writer has not taken; ask again with acknowledgeQuality: true and the same key to send it as written. The API and MCP are never reminded.
| Field | Type | Notes |
|---|---|---|
draft | object | required |
draft. | "single_choice" | | required |
draft. | string | required up to 600 characters |
draft. | string | up to 120 characters |
draft. | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
draft. | object[] | up to 8 items, default [] |
draft. | string | required up to 40 characters |
draft. | string (URL) | |
draft. | string (URL)[] | up to 4 items |
draft. | object | |
draft. | string | required up to 24 characters |
draft. | string | required up to 24 characters |
draft. | boolean | default false |
draft. | object | |
draft. | string (URL) | |
draft. | string (URL) | |
draft. | string | up to 120 characters |
draft. | integer | 2000–10000 |
draft. | integer | 10–5000, default 50 |
draft. | 1 | | default 1 |
draft. | boolean | default false |
draft. | object | |
draft. | string[] | up to 50 items, default [] |
draft. | string[] | up to 20 items, default [] |
draft. | "18-24" | | up to 6 items |
draft. | "woman" | | up to 3 items |
draft. | boolean | |
draft. | object | |
draft. | integer | 1–5, default 1 |
draft. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
draft. | boolean | default false |
draft. | "off" | | default "off" |
draft. | object | |
draft. | number | required 0.5–0.95 |
draft. | integer | required 5–5000 |
draft. | "none" | | |
draft. | string | up to 40 characters |
draft. | 1 | | |
draft. | object | |
draft. | integer | required 1–10000 |
draft. | integer | required 0–10000 |
draft. | "heads" | | default "heads" |
draft. | 1 | | default 7 |
draft. | string | up to 40 characters |
fromDraftId | string | |
then | object[] | up to 3 items |
then[] | "single_choice" | | default "free_text" |
then[] | string | required up to 600 characters, at least 8 characters |
then[] | object[] | up to 8 items, default [] |
then[] | string | required up to 40 characters |
then[] | string (URL) | |
then[] | string (URL)[] | up to 4 items |
then[] | integer | 10–5000, default 20 |
then[] | 1 | | default 2 |
then[] | "low" | | |
then[] | "off" | | |
variantOf | string | |
followUpOf | string | up to 64 characters |
templateId | string | |
projectId | string | | |
labels | string[] | up to 10 items |
externalRef | string | up to 100 characters, pattern ^[\w.:\-/#@+]+$ |
privateDeclaration | object | |
privateDeclaration. | integer | required ≥ 1 |
acknowledgeQuality | boolean |
| Field | Type | Notes |
|---|---|---|
question | object | required |
question. | "single_choice" | | required |
question. | string | required up to 600 characters |
question. | string | up to 120 characters |
question. | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
question. | object[] | required up to 8 items, default [] |
question. | string | required up to 40 characters |
question. | string (URL) | |
question. | string (URL)[] | up to 4 items |
question. | object | |
question. | string | required up to 24 characters |
question. | string | required up to 24 characters |
question. | boolean | required default false |
question. | object | |
question. | string (URL) | |
question. | string (URL) | |
question. | string | up to 120 characters |
question. | integer | 2000–10000 |
question. | integer | required 10–5000, default 50 |
question. | 1 | | required default 1 |
question. | boolean | required default false |
question. | object | |
question. | string[] | required up to 50 items, default [] |
question. | string[] | required up to 20 items, default [] |
question. | "18-24" | | up to 6 items |
question. | "woman" | | up to 3 items |
question. | boolean | |
question. | object | |
question. | integer | required 1–5, default 1 |
question. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
question. | boolean | required default false |
question. | "off" | | required default "off" |
question. | object | |
question. | number | required 0.5–0.95 |
question. | integer | required 5–5000 |
question. | "none" | | |
question. | string | up to 40 characters |
question. | 1 | | |
question. | object | |
question. | integer | required 1–10000 |
question. | integer | required 0–10000 |
question. | "heads" | | required default "heads" |
question. | 1 | | required default 7 |
question. | string | up to 40 characters |
question. | string | required |
question. | "draft" | | required |
question. | "app" | | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | string | | required |
question. | string | | required |
question. | string | | required |
question. | string | required |
question. | string | | required |
question. | string | | required |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | | required |
question. | string | | |
question. | string[] | |
question. | boolean | |
question. | boolean | |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | required |
question. | string | required |
question. | string | | required |
question. | integer | required |
question. | integer | required |
question. | string | | |
question. | integer | | |
question. | integer | |
GET/v2/questions
Your questions, newest first.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
status | "draft" | | |
since | string | |
limit | integer | 1–100 |
cursor | string | |
projectId | string | |
label | string | |
externalRef | string | |
archived | "exclude" | | |
bookmarked | boolean | |
mine | boolean | |
setId | string |
| Field | Type | Notes |
|---|---|---|
questions | object[] | required |
questions[] | "single_choice" | | required |
questions[] | string | required up to 600 characters |
questions[] | string | up to 120 characters |
questions[] | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
questions[] | object[] | required up to 8 items, default [] |
questions[] | string | required up to 40 characters |
questions[] | string (URL) | |
questions[] | string (URL)[] | up to 4 items |
questions[] | object | |
questions[] | string | required up to 24 characters |
questions[] | string | required up to 24 characters |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string (URL) | |
questions[] | string (URL) | |
questions[] | string | up to 120 characters |
questions[] | integer | 2000–10000 |
questions[] | integer | required 10–5000, default 50 |
questions[] | 1 | | required default 1 |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string[] | required up to 50 items, default [] |
questions[] | string[] | required up to 20 items, default [] |
questions[] | "18-24" | | up to 6 items |
questions[] | "woman" | | up to 3 items |
questions[] | boolean | |
questions[] | object | |
questions[] | integer | required 1–5, default 1 |
questions[] | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
questions[] | boolean | required default false |
questions[] | "off" | | required default "off" |
questions[] | object | |
questions[] | number | required 0.5–0.95 |
questions[] | integer | required 5–5000 |
questions[] | "none" | | |
questions[] | string | up to 40 characters |
questions[] | 1 | | |
questions[] | object | |
questions[] | integer | required 1–10000 |
questions[] | integer | required 0–10000 |
questions[] | "heads" | | required default "heads" |
questions[] | 1 | | required default 7 |
questions[] | string | up to 40 characters |
questions[] | string | required |
questions[] | "draft" | | required |
questions[] | "app" | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | string[] | |
questions[] | boolean | |
questions[] | boolean | |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | |
questions[] | integer | | |
questions[] | integer | | |
nextCursor | string | | required |
GET/v2/questions/{id}
One question and its progress.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
question | object | required |
question. | "single_choice" | | required |
question. | string | required up to 600 characters |
question. | string | up to 120 characters |
question. | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
question. | object[] | required up to 8 items, default [] |
question. | string | required up to 40 characters |
question. | string (URL) | |
question. | string (URL)[] | up to 4 items |
question. | object | |
question. | string | required up to 24 characters |
question. | string | required up to 24 characters |
question. | boolean | required default false |
question. | object | |
question. | string (URL) | |
question. | string (URL) | |
question. | string | up to 120 characters |
question. | integer | 2000–10000 |
question. | integer | required 10–5000, default 50 |
question. | 1 | | required default 1 |
question. | boolean | required default false |
question. | object | |
question. | string[] | required up to 50 items, default [] |
question. | string[] | required up to 20 items, default [] |
question. | "18-24" | | up to 6 items |
question. | "woman" | | up to 3 items |
question. | boolean | |
question. | object | |
question. | integer | required 1–5, default 1 |
question. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
question. | boolean | required default false |
question. | "off" | | required default "off" |
question. | object | |
question. | number | required 0.5–0.95 |
question. | integer | required 5–5000 |
question. | "none" | | |
question. | string | up to 40 characters |
question. | 1 | | |
question. | object | |
question. | integer | required 1–10000 |
question. | integer | required 0–10000 |
question. | "heads" | | required default "heads" |
question. | 1 | | required default 7 |
question. | string | up to 40 characters |
question. | string | required |
question. | "draft" | | required |
question. | "app" | | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | string | | required |
question. | string | | required |
question. | string | | required |
question. | string | required |
question. | string | | required |
question. | string | | required |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | | required |
question. | string | | |
question. | string[] | |
question. | boolean | |
question. | boolean | |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | required |
question. | string | required |
question. | string | | required |
question. | integer | required |
question. | integer | required |
question. | string | | |
question. | integer | | |
question. | integer | |
PATCH/v2/questions/{id}
Complete early once minAnswers heads have answered, or file it: project, labels, archive, bookmark and a set-once externalRef.
API key or OAuth token with questions:write.
If that many have already answered, the question closes now and what was not answered is refunded. Changing an externalRef once set is refused with 409 external_ref_set.
| Field | Type | Notes |
|---|---|---|
minAnswers | integer | 1–5000 |
projectId | string | | |
labels | string[] | up to 10 items |
archived | boolean | |
bookmarked | boolean | |
externalRef | string | up to 100 characters, pattern ^[\w.:\-/#@+]+$ |
| Field | Type | Notes |
|---|---|---|
question | object | required |
question. | "single_choice" | | required |
question. | string | required up to 600 characters |
question. | string | up to 120 characters |
question. | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
question. | object[] | required up to 8 items, default [] |
question. | string | required up to 40 characters |
question. | string (URL) | |
question. | string (URL)[] | up to 4 items |
question. | object | |
question. | string | required up to 24 characters |
question. | string | required up to 24 characters |
question. | boolean | required default false |
question. | object | |
question. | string (URL) | |
question. | string (URL) | |
question. | string | up to 120 characters |
question. | integer | 2000–10000 |
question. | integer | required 10–5000, default 50 |
question. | 1 | | required default 1 |
question. | boolean | required default false |
question. | object | |
question. | string[] | required up to 50 items, default [] |
question. | string[] | required up to 20 items, default [] |
question. | "18-24" | | up to 6 items |
question. | "woman" | | up to 3 items |
question. | boolean | |
question. | object | |
question. | integer | required 1–5, default 1 |
question. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
question. | boolean | required default false |
question. | "off" | | required default "off" |
question. | object | |
question. | number | required 0.5–0.95 |
question. | integer | required 5–5000 |
question. | "none" | | |
question. | string | up to 40 characters |
question. | 1 | | |
question. | object | |
question. | integer | required 1–10000 |
question. | integer | required 0–10000 |
question. | "heads" | | required default "heads" |
question. | 1 | | required default 7 |
question. | string | up to 40 characters |
question. | string | required |
question. | "draft" | | required |
question. | "app" | | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | string | | required |
question. | string | | required |
question. | string | | required |
question. | string | required |
question. | string | | required |
question. | string | | required |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | | required |
question. | string | | |
question. | string[] | |
question. | boolean | |
question. | boolean | |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | required |
question. | string | required |
question. | string | | required |
question. | integer | required |
question. | integer | required |
question. | string | | |
question. | integer | | |
question. | integer | |
GET/v2/questions/labels
Labels in use in the account, most used first.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
labels | object[] | required |
labels[] | string | required |
labels[] | integer | required |
GET/v2/questions/{id}/result
The result so far. Partial while the question is live.
API key or OAuth token with questions:read.
With a filter, the distribution, breakdowns and answers are of matching answers only; nUnfiltered counts them all and suppressed is true when a country or age band matched too few to show. insights is the summary of written answers once there is one.
| Field | Type | Notes |
|---|---|---|
option | integer | 0–8 |
tier | integer | 1–3 |
country | string | up to 2 characters, at least 2 characters |
age_band | string | |
q | string | up to 100 characters |
| Field | Type | Notes |
|---|---|---|
result | object | required |
result. | string | required |
result. | "in_progress" | | required |
result. | integer | required |
result. | integer | required |
result. | object[] | required |
result. | string | required |
result. | integer | required |
result. | number | required |
result. | number | |
result. | number | |
result. | integer[] | up to 5 items |
result. | integer | |
result. | number | |
result. | integer | |
result. | number | |
result. | number | |
result. | number | | required |
result. | object | | |
result. | string | required up to 24 characters |
result. | string | required up to 24 characters |
result. | object | required |
result. | string | | required |
result. | number | | required |
result. | "low" | | required |
result. | string | required |
result. | string | | required |
result. | integer | | required |
result. | string | required |
result. | string | required |
result. | object | |
result. | "heads" | | required |
result. | "app" | | required |
result. | boolean | required |
result. | integer | required |
result. | integer | | required |
result. | "known" | | required |
result. | number | | required |
result. | integer | required |
result. | object[] | required |
result. | string | | required |
result. | string | | required |
result. | string | | |
result. | string | | |
result. | string | | |
result. | integer | | required |
result. | string | | required |
result. | string | required |
result. | boolean | |
result. | object | | |
result. | object[] | |
result. | object | |
result. | object[] | |
result. | string | required |
result. | string | required |
result. | integer | required |
result. | object[] | required |
result. | integer | required |
result. | object[] | |
result. | "country" | | required |
result. | object[] | required |
result. | object | |
result. | string | | required |
result. | integer | required |
result. | object[] | required |
result. | integer[] | required |
result. | integer | required |
result. | object[] | required |
result. | string | | required |
result. | object | |
result. | number | required |
result. | number | required |
result. | number | required |
result. | string | | |
result. | object | | |
result. | string | required |
result. | string | required |
result. | string | required |
result. | string | required |
result. | object[] | required up to 8 items |
result. | object[] | up to 5 items |
result. | object[] | up to 9 items |
result. | object | | |
result. | object | required |
result. | integer | required |
result. | integer | required |
result. | object | | required |
result. | "interim" | | required |
result. | string | required |
result. | string | | required |
result. | string | required |
result. | object | |
result. | integer | 0–8 |
result. | integer | 1–3 |
result. | object | |
result. | string | pattern ^[0-9]{2}(-[0-9]{2}|\+)$ |
result. | "woman" | | |
result. | string | up to 100 characters |
result. | integer | |
result. | boolean | |
result. | object | |
result. | object[] | required |
result. | object[] | required |
result. | object[] | required |
result. | object[] | |
result. | object | |
result. | "go" | | required |
result. | "too_few" | | required |
result. | number | required |
result. | number | required |
result. | number | required |
result. | number | required |
result. | integer | required |
result. | integer | required |
result. | object | |
result. | string[] | required |
result. | number | | required |
result. | integer[][] | required |
result. | string |
GET/v2/questions/{id}/answers
Matching answers, newest first, a page at a time, with reasons and translations.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
option | integer | 0–8 |
tier | integer | 1–3 |
country | string | up to 2 characters, at least 2 characters |
age_band | string | |
q | string | up to 100 characters |
limit | integer | 1–200 |
cursor | string | up to 200 characters |
| Field | Type | Notes |
|---|---|---|
questionId | string | required |
filter | object | required |
filter. | integer | 0–8 |
filter. | integer | 1–3 |
filter. | object | |
filter. | string | pattern ^[0-9]{2}(-[0-9]{2}|\+)$ |
filter. | "woman" | | |
filter. | string | up to 100 characters |
total | integer | required |
nUnfiltered | integer | required |
suppressed | boolean | required |
answers | object[] | required |
answers[] | string | | required |
answers[] | string | | required |
answers[] | string | | |
answers[] | string | | |
answers[] | string | | |
answers[] | integer | | required |
answers[] | string | | required |
answers[] | string | required |
answers[] | boolean | |
answers[] | object | | |
answers[] | "off_topic" | | required |
answers[] | "open" | | required |
answers[] | integer | required |
answers[] | string | required |
answers[] | string | | required |
answers[] | object[] | |
answers[] | number | required 0–1 |
answers[] | number | required 0–1 |
answers[] | object | |
answers[] | integer | |
answers[] | integer[] | |
answers[] | integer[] | |
answers[] | array | up to 2 items |
answers[] | integer[] | |
translationLanguage | string | | required |
nextCursor | string | | required |
GET/v2/questions/{id}/insights
The summary of the written answers: themes with counts and quotes, sentiment, a takeaway.
API key or OAuth token with questions:read.
Made by a machine from the reasons and free text, never from who answered; counts and quotes are computed from the answers. Written in the account's language, with the question-language original.
| Field | Type | Notes |
|---|---|---|
insights | object | | required |
insights. | string | required |
insights. | string | required |
insights. | string | required |
insights. | string | required |
insights. | object[] | required up to 8 items |
insights. | string | required |
insights. | integer | required |
insights. | number | required |
insights. | "positive" | | required |
insights. | string | | required |
insights. | string[] | required up to 3 items |
insights. | object[] | up to 5 items |
insights. | string | required |
insights. | integer | required |
insights. | string | | required |
insights. | string[] | required up to 3 items |
insights. | object[] | up to 9 items |
insights. | string | required |
insights. | integer | required |
insights. | object[] | required up to 4 items |
insights. | object[] | required up to 4 items |
insights. | object | | |
insights. | "single_choice" | | required |
insights. | string | required |
insights. | string[] | required up to 8 items |
insights. | integer | required 10–5000 |
insights. | 1 | | required |
insights. | "off" | | required |
insights. | object | required |
insights. | integer | required |
insights. | integer | required |
insights. | integer | required |
insights. | integer | required |
insights. | integer | required |
insights. | object | | required |
insights. | string | required |
insights. | object[] | required |
insights. | object[] | |
insights. | object | | |
insights. | "interim" | | required |
insights. | string | required |
insights. | string | | required |
insights. | string | required |
POST/v2/questions/{id}/insights
Make a fresh summary now: once every 10 minutes while live; the final one when it closes.
API key or OAuth token with questions:read.
429 rate_limited with retryAfterMs while a recent summary stands; 409 too_few_answers under three written answers.
| Field | Type | Notes |
|---|---|---|
insights | object | | required |
insights. | string | required |
insights. | string | required |
insights. | string | required |
insights. | string | required |
insights. | object[] | required up to 8 items |
insights. | string | required |
insights. | integer | required |
insights. | number | required |
insights. | "positive" | | required |
insights. | string | | required |
insights. | string[] | required up to 3 items |
insights. | object[] | up to 5 items |
insights. | string | required |
insights. | integer | required |
insights. | string | | required |
insights. | string[] | required up to 3 items |
insights. | object[] | up to 9 items |
insights. | string | required |
insights. | integer | required |
insights. | object[] | required up to 4 items |
insights. | object[] | required up to 4 items |
insights. | object | | |
insights. | "single_choice" | | required |
insights. | string | required |
insights. | string[] | required up to 8 items |
insights. | integer | required 10–5000 |
insights. | 1 | | required |
insights. | "off" | | required |
insights. | object | required |
insights. | integer | required |
insights. | integer | required |
insights. | integer | required |
insights. | integer | required |
insights. | integer | required |
insights. | object | | required |
insights. | string | required |
insights. | object[] | required |
insights. | object[] | |
insights. | object | | |
insights. | "interim" | | required |
insights. | string | required |
insights. | string | | required |
insights. | string | required |
GET/v2/questions/{id}/wait
Hold the request until the question is answered, up to 25 seconds a call.
API key or OAuth token with questions:read.
Call again while done is false. minAnswers completes early once that many heads have answered.
| Field | Type | Notes |
|---|---|---|
seconds | integer | 1–25 |
minAnswers | integer | ≥ 1 |
| Field | Type | Notes |
|---|---|---|
result | object | required |
result. | string | required |
result. | "in_progress" | | required |
result. | integer | required |
result. | integer | required |
result. | object[] | required |
result. | string | required |
result. | integer | required |
result. | number | required |
result. | number | |
result. | number | |
result. | integer[] | up to 5 items |
result. | integer | |
result. | number | |
result. | integer | |
result. | number | |
result. | number | |
result. | number | | required |
result. | object | | |
result. | string | required up to 24 characters |
result. | string | required up to 24 characters |
result. | object | required |
result. | string | | required |
result. | number | | required |
result. | "low" | | required |
result. | string | required |
result. | string | | required |
result. | integer | | required |
result. | string | required |
result. | string | required |
result. | object | |
result. | "heads" | | required |
result. | "app" | | required |
result. | boolean | required |
result. | integer | required |
result. | integer | | required |
result. | "known" | | required |
result. | number | | required |
result. | integer | required |
result. | object[] | required |
result. | string | | required |
result. | string | | required |
result. | string | | |
result. | string | | |
result. | string | | |
result. | integer | | required |
result. | string | | required |
result. | string | required |
result. | boolean | |
result. | object | | |
result. | object[] | |
result. | object | |
result. | object[] | |
result. | string | required |
result. | string | required |
result. | integer | required |
result. | object[] | required |
result. | integer | required |
result. | object[] | |
result. | "country" | | required |
result. | object[] | required |
result. | object | |
result. | string | | required |
result. | integer | required |
result. | object[] | required |
result. | integer[] | required |
result. | integer | required |
result. | object[] | required |
result. | string | | required |
result. | object | |
result. | number | required |
result. | number | required |
result. | number | required |
result. | string | | |
result. | object | | |
result. | string | required |
result. | string | required |
result. | string | required |
result. | string | required |
result. | object[] | required up to 8 items |
result. | object[] | up to 5 items |
result. | object[] | up to 9 items |
result. | object | | |
result. | object | required |
result. | integer | required |
result. | integer | required |
result. | object | | required |
result. | "interim" | | required |
result. | string | required |
result. | string | | required |
result. | string | required |
result. | object | |
result. | integer | 0–8 |
result. | integer | 1–3 |
result. | object | |
result. | string | pattern ^[0-9]{2}(-[0-9]{2}|\+)$ |
result. | "woman" | | |
result. | string | up to 100 characters |
result. | integer | |
result. | boolean | |
result. | object | |
result. | object[] | required |
result. | object[] | required |
result. | object[] | required |
result. | object[] | |
result. | object | |
result. | "go" | | required |
result. | "too_few" | | required |
result. | number | required |
result. | number | required |
result. | number | required |
result. | number | required |
result. | integer | required |
result. | integer | required |
result. | object | |
result. | string[] | required |
result. | number | | required |
result. | integer[][] | required |
result. | string | |
done | boolean | required |
POST/v2/questions/{id}/cancel
Stop a live question and refund the answers not given.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
question | object | required |
question. | "single_choice" | | required |
question. | string | required up to 600 characters |
question. | string | up to 120 characters |
question. | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
question. | object[] | required up to 8 items, default [] |
question. | string | required up to 40 characters |
question. | string (URL) | |
question. | string (URL)[] | up to 4 items |
question. | object | |
question. | string | required up to 24 characters |
question. | string | required up to 24 characters |
question. | boolean | required default false |
question. | object | |
question. | string (URL) | |
question. | string (URL) | |
question. | string | up to 120 characters |
question. | integer | 2000–10000 |
question. | integer | required 10–5000, default 50 |
question. | 1 | | required default 1 |
question. | boolean | required default false |
question. | object | |
question. | string[] | required up to 50 items, default [] |
question. | string[] | required up to 20 items, default [] |
question. | "18-24" | | up to 6 items |
question. | "woman" | | up to 3 items |
question. | boolean | |
question. | object | |
question. | integer | required 1–5, default 1 |
question. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
question. | boolean | required default false |
question. | "off" | | required default "off" |
question. | object | |
question. | number | required 0.5–0.95 |
question. | integer | required 5–5000 |
question. | "none" | | |
question. | string | up to 40 characters |
question. | 1 | | |
question. | object | |
question. | integer | required 1–10000 |
question. | integer | required 0–10000 |
question. | "heads" | | required default "heads" |
question. | 1 | | required default 7 |
question. | string | up to 40 characters |
question. | string | required |
question. | "draft" | | required |
question. | "app" | | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | string | | required |
question. | string | | required |
question. | string | | required |
question. | string | required |
question. | string | | required |
question. | string | | required |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | | required |
question. | string | | |
question. | string[] | |
question. | boolean | |
question. | boolean | |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | required |
question. | string | required |
question. | string | | required |
question. | integer | required |
question. | integer | required |
question. | string | | |
question. | integer | | |
question. | integer | | |
refundCredits | integer | required |
POST/v2/questions/{id}/rating
Say how useful the answers were, from 1 to 5.
API key or OAuth token with questions:write.
Once the question has at least one answer (409 nothing_to_rate before). Sending it again replaces the earlier rating.
| Field | Type | Notes |
|---|---|---|
usefulness | integer | required 1–5 |
| Field | Type | Notes |
|---|---|---|
ok | true | required |
GET/v2/questions/{id}/export.csv
Every answer as CSV: option or text, reason, translations, tier, attestation reference, time, and taps for a click test.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
option | integer | 0–8 |
tier | integer | 1–3 |
country | string | up to 2 characters, at least 2 characters |
age_band | string | |
q | string | up to 100 characters |
GET/v2/questions/{id}/export.jsonl
Every answer as JSON lines (application/x-ndjson), for scripts and model training: the CSV's fields plus `choice` (option indexes) and `cohortHash`.
API key or OAuth token with questions:read.
One JSON object per answer, each on its own line and newline-terminated; an empty body when no answers match. Takes the same filters as export.csv. Nothing identifies a head.
| Field | Type | Notes |
|---|---|---|
option | integer | 0–8 |
tier | integer | 1–3 |
country | string | up to 2 characters, at least 2 characters |
age_band | string | |
q | string | up to 100 characters |
GET/v2/questions/{id}/link/qr.svg
Your audience: the share link's QR code as SVG (quiet zone of four modules, error correction M).
API key or OAuth token with questions:read.
GET/v2/questions/{id}/link/qr.png
Your audience: the share link's QR code as a 1024-pixel PNG.
API key or OAuth token with questions:read.
GET/v2/questions/{id}/export.pdf
A one-page PDF report: the question, the chart, what it means and the answers (pinned first).
API key or OAuth token with questions:read.
GET/v2/questions/{id}/export.png
The chart as a PNG to share: size=square (1080×1080, default), wide (1200×675) or story (1080×1920).
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
size | "square" | |
POST/v2/questions/{id}/exports
A PDF report or PNG chart as a signed link that works for an hour without signing in.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
format | "pdf" | | required |
size | "square" | |
| Field | Type | Notes |
|---|---|---|
export | object | required |
export. | "pdf" | | required |
export. | "square" | | required |
export. | string | required |
export. | string | required |
export. | string | required |
POST/v2/questions/{id}/heads
Reopen a finished question for n more heads, same wording and targeting; answers merge. dryRun quotes only.
API key or OAuth token with questions:write. Idempotency-Key header required.
Needs an Idempotency-Key unless dryRun. The question must be complete or underfilled.
| Field | Type | Notes |
|---|---|---|
n | integer | required 1–5000 |
dryRun | boolean |
| Field | Type | Notes |
|---|---|---|
question | object | |
question. | "single_choice" | | required |
question. | string | required up to 600 characters |
question. | string | up to 120 characters |
question. | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
question. | object[] | required up to 8 items, default [] |
question. | string | required up to 40 characters |
question. | string (URL) | |
question. | string (URL)[] | up to 4 items |
question. | object | |
question. | string | required up to 24 characters |
question. | string | required up to 24 characters |
question. | boolean | required default false |
question. | object | |
question. | string (URL) | |
question. | string (URL) | |
question. | string | up to 120 characters |
question. | integer | 2000–10000 |
question. | integer | required 10–5000, default 50 |
question. | 1 | | required default 1 |
question. | boolean | required default false |
question. | object | |
question. | string[] | required up to 50 items, default [] |
question. | string[] | required up to 20 items, default [] |
question. | "18-24" | | up to 6 items |
question. | "woman" | | up to 3 items |
question. | boolean | |
question. | object | |
question. | integer | required 1–5, default 1 |
question. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
question. | boolean | required default false |
question. | "off" | | required default "off" |
question. | object | |
question. | number | required 0.5–0.95 |
question. | integer | required 5–5000 |
question. | "none" | | |
question. | string | up to 40 characters |
question. | 1 | | |
question. | object | |
question. | integer | required 1–10000 |
question. | integer | required 0–10000 |
question. | "heads" | | required default "heads" |
question. | 1 | | required default 7 |
question. | string | up to 40 characters |
question. | string | required |
question. | "draft" | | required |
question. | "app" | | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | string | | required |
question. | string | | required |
question. | string | | required |
question. | string | required |
question. | string | | required |
question. | string | | required |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | | required |
question. | string | | |
question. | string[] | |
question. | boolean | |
question. | boolean | |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | required |
question. | string | required |
question. | string | | required |
question. | integer | required |
question. | integer | required |
question. | string | | |
question. | integer | | |
question. | integer | | |
quote | object | required |
quote. | integer | required |
quote. | integer | required |
quote. | integer | required |
quote. | integer | required |
quote. | integer | required |
quote. | string | required |
creditsReserved | integer |
POST/v2/questions/{id}/answers/{ref}/flag
Flag one answer, named by its attestation reference, for review. Upheld: removed and refunded.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
reason | "off_topic" | | required |
note | string | up to 500 characters |
| Field | Type | Notes |
|---|---|---|
flag | object | required |
flag. | "off_topic" | | required |
flag. | "open" | | required |
flag. | integer | required |
flag. | string | required |
flag. | string | | required |
flag. | string | required |
flag. | string | required |
POST/v2/questions/{id}/answers/{ref}/pin
Pin an answer to the top of the results and the PDF report, or unpin it.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
pinned | boolean | required |
| Field | Type | Notes |
|---|---|---|
pinned | boolean | required |
GET/v1/public/link/{code}
Your audience: what the answer page shows for a link. No sign-in; never cached; noindex.
No authentication.
The page for /y/{code}. Returns the question, the "Shown as" name and the link's state (live, scheduled, closed, full or paused) and nothing about the owner, the price or the counts.
| Field | Type | Notes |
|---|---|---|
kind | "question" | | required |
state | "live" | | required |
shownAs | string | | required |
language | string | required |
question | object | | required |
question. | string | required |
question. | string | required |
question. | string | | required |
question. | string | required |
question. | object[] | required |
question. | string | required |
question. | string | | required |
question. | string[] | |
question. | boolean | required |
question. | object | | |
question. | string | required up to 24 characters |
question. | string | required up to 24 characters |
question. | object | | required |
question. | string | | required |
question. | string | | required |
question. | string | | required |
question. | integer | | required |
question. | array | | required |
opensAt | string | | required |
showResult | boolean | required |
resultCode | string | | required |
set | object | | required |
set. | integer | required ≥ 1 |
set. | object[] | required |
set. | integer | required ≥ 1 |
set. | "live" | | required |
set. | object | | required |
POST/v1/public/link/{code}/answers
Your audience: one answer from the browser.
No authentication.
Needs a Turnstile token in production and a fresh UUID nonce per page load: a retry with the same nonce returns the first outcome. Fails with human_check_failed (403) or rate_limited (429). An answer after the link closed or filled returns accepted: false with the state to show.
| Field | Type | Notes |
|---|---|---|
answer | object | required |
answer. | integer | 0–8 |
answer. | integer[] | up to 9 items |
answer. | integer[] | up to 9 items |
answer. | integer[] | up to 8 items |
answer. | array | up to 2 items |
answer. | object[] | up to 5 items |
answer. | number | required 0–1 |
answer. | number | required 0–1 |
dwellMs | integer | 0–86400000, default 0 |
interrupted | boolean | default false |
nonce | string (uuid) | required pattern ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$ |
turnstileToken | string | up to 2048 characters |
locale | string | up to 12 characters |
position | integer | 1–10 |
visit | string | up to 40 characters |
| Field | Type | Notes |
|---|---|---|
accepted | boolean | required |
state | "live" | | required |
showResult | boolean | required |
resultCode | string | | required |
visit | string | | required |
remaining | integer[] | required |
answered | object[] | required |
answered[] | integer | required |
answered[] | string | | required |
POST/v1/public/link/{code}/started
Your audience: an option was chosen on the answer page.
No authentication. Idempotency-Key header required.
Counted once per page load (the nonce), so the link's started figure means people, not loads.
| Field | Type | Notes |
|---|---|---|
nonce | string (uuid) | required pattern ^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$ |
| Field | Type | Notes |
|---|---|---|
ok | true | required |
GET/v2/questions/{id}/heatmap.png
A click test's heatmap as a transparent PNG to lay over the image. Add ?aspect=width/height to match it.
API key or OAuth token with questions:read.
POST/v2/questions/{id}/dispute
Dispute a result within 7 days of it closing.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
reason | string | required up to 2000 characters, at least 10 characters |
| Field | Type | Notes |
|---|---|---|
ok | true | required |
GET/v1/public/results/{code}
A result its requester made public.
No authentication.
| Field | Type | Notes |
|---|---|---|
question | object | required |
question. | "single_choice" | | required |
question. | string | required up to 600 characters |
question. | string | up to 120 characters |
question. | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
question. | object[] | required up to 8 items, default [] |
question. | string | required up to 40 characters |
question. | string (URL) | |
question. | string (URL)[] | up to 4 items |
question. | object | |
question. | string | required up to 24 characters |
question. | string | required up to 24 characters |
question. | boolean | required default false |
question. | object | |
question. | string (URL) | |
question. | string (URL) | |
question. | string | up to 120 characters |
question. | integer | 2000–10000 |
question. | integer | required 10–5000, default 50 |
question. | 1 | | required default 1 |
question. | boolean | required default false |
question. | object | |
question. | string[] | required up to 50 items, default [] |
question. | string[] | required up to 20 items, default [] |
question. | "18-24" | | up to 6 items |
question. | "woman" | | up to 3 items |
question. | boolean | |
question. | object | |
question. | integer | required 1–5, default 1 |
question. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
question. | boolean | required default false |
question. | "off" | | required default "off" |
question. | object | |
question. | number | required 0.5–0.95 |
question. | integer | required 5–5000 |
question. | "none" | | |
question. | string | up to 40 characters |
question. | 1 | | |
question. | object | |
question. | integer | required 1–10000 |
question. | integer | required 0–10000 |
question. | "heads" | | required default "heads" |
question. | 1 | | required default 7 |
question. | string | up to 40 characters |
question. | string | required |
question. | "draft" | | required |
question. | "app" | | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | integer | required |
question. | string | | required |
question. | string | | required |
question. | string | | required |
question. | string | required |
question. | string | | required |
question. | string | | required |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | | required |
question. | string | | |
question. | string[] | |
question. | boolean | |
question. | boolean | |
question. | string | | |
question. | object | | |
question. | string | required |
question. | string | required |
question. | string | required |
question. | string | | required |
question. | integer | required |
question. | integer | required |
question. | string | | |
question. | integer | | |
question. | integer | | |
result | object | required |
result. | string | required |
result. | "in_progress" | | required |
result. | integer | required |
result. | integer | required |
result. | object[] | required |
result. | string | required |
result. | integer | required |
result. | number | required |
result. | number | |
result. | number | |
result. | integer[] | up to 5 items |
result. | integer | |
result. | number | |
result. | integer | |
result. | number | |
result. | number | |
result. | number | | required |
result. | object | | |
result. | string | required up to 24 characters |
result. | string | required up to 24 characters |
result. | object | required |
result. | string | | required |
result. | number | | required |
result. | "low" | | required |
result. | string | required |
result. | string | | required |
result. | integer | | required |
result. | string | required |
result. | string | required |
result. | object | |
result. | "heads" | | required |
result. | "app" | | required |
result. | boolean | required |
result. | integer | required |
result. | integer | | required |
result. | "known" | | required |
result. | number | | required |
result. | integer | required |
result. | object[] | required |
result. | string | | required |
result. | string | | required |
result. | string | | |
result. | string | | |
result. | string | | |
result. | integer | | required |
result. | string | | required |
result. | string | required |
result. | boolean | |
result. | object | | |
result. | object[] | |
result. | object | |
result. | object[] | |
result. | string | required |
result. | string | required |
result. | integer | required |
result. | object[] | required |
result. | integer | required |
result. | object[] | |
result. | "country" | | required |
result. | object[] | required |
result. | object | |
result. | string | | required |
result. | integer | required |
result. | object[] | required |
result. | integer[] | required |
result. | integer | required |
result. | object[] | required |
result. | string | | required |
result. | object | |
result. | number | required |
result. | number | required |
result. | number | required |
result. | string | | |
result. | object | | |
result. | string | required |
result. | string | required |
result. | string | required |
result. | string | required |
result. | object[] | required up to 8 items |
result. | object[] | up to 5 items |
result. | object[] | up to 9 items |
result. | object | | |
result. | object | required |
result. | integer | required |
result. | integer | required |
result. | object | | required |
result. | "interim" | | required |
result. | string | required |
result. | string | | required |
result. | string | required |
result. | object | |
result. | integer | 0–8 |
result. | integer | 1–3 |
result. | object | |
result. | string | pattern ^[0-9]{2}(-[0-9]{2}|\+)$ |
result. | "woman" | | |
result. | string | up to 100 characters |
result. | integer | |
result. | boolean | |
result. | object | |
result. | object[] | required |
result. | object[] | required |
result. | object[] | required |
result. | object[] | |
result. | object | |
result. | "go" | | required |
result. | "too_few" | | required |
result. | number | required |
result. | number | required |
result. | number | required |
result. | number | required |
result. | integer | required |
result. | integer | required |
result. | object | |
result. | string[] | required |
result. | number | | required |
result. | integer[][] | required |
result. | string |
Sets
Your audience: two to ten questions behind one link, answered in order. Each question in a set is an ordinary question with its own result and exports; the set owns the link and the closing date.
POST/v2/sets
Your audience: publish a set of two to ten questions behind one link.
API key or OAuth token with questions:write. Idempotency-Key header required.
Requires an Idempotency-Key header (a UUID); the same key returns the same set. Every question is reserved at 5 credits an answer times maxAnswers. Fails with insufficient_credits, private_link_limit, private_declaration_required or content_refused without spending anything.
| Field | Type | Notes |
|---|---|---|
questions | object[] | required up to 10 items |
questions[] | "single_choice" | | required |
questions[] | string | required up to 600 characters |
questions[] | string | up to 120 characters |
questions[] | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
questions[] | object[] | up to 8 items, default [] |
questions[] | string | required up to 40 characters |
questions[] | string (URL) | |
questions[] | string (URL)[] | up to 4 items |
questions[] | object | |
questions[] | string | required up to 24 characters |
questions[] | string | required up to 24 characters |
questions[] | boolean | default false |
questions[] | object | |
questions[] | string (URL) | |
questions[] | string (URL) | |
questions[] | string | up to 120 characters |
questions[] | integer | 2000–10000 |
questions[] | object | |
questions[] | integer | 1–5, default 1 |
questions[] | object | |
questions[] | number | required 0.5–0.95 |
questions[] | integer | required 5–5000 |
maxAnswers | integer | 10–5000, default 100 |
openForDays | 1 | | default 7 |
shownAs | string | up to 40 characters |
publicResults | boolean | default false |
projectId | string | | |
labels | string[] | up to 10 items |
privateDeclaration | object | |
privateDeclaration. | integer | required ≥ 1 |
| Field | Type | Notes |
|---|---|---|
set | object | required |
set. | string | required |
set. | "open" | | required |
set. | string | | required |
set. | integer | required |
set. | 1 | | required |
set. | boolean | required |
set. | string | required |
set. | string[] | required |
set. | integer | required |
set. | integer | required |
set. | integer | required |
set. | object | | required |
set. | string | required |
set. | string | required |
set. | string | required |
set. | string | | required |
set. | integer | required |
set. | integer | required |
set. | string | | required |
set. | string | required |
set. | string | | required |
questions | object[] | required |
questions[] | "single_choice" | | required |
questions[] | string | required up to 600 characters |
questions[] | string | up to 120 characters |
questions[] | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
questions[] | object[] | required up to 8 items, default [] |
questions[] | string | required up to 40 characters |
questions[] | string (URL) | |
questions[] | string (URL)[] | up to 4 items |
questions[] | object | |
questions[] | string | required up to 24 characters |
questions[] | string | required up to 24 characters |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string (URL) | |
questions[] | string (URL) | |
questions[] | string | up to 120 characters |
questions[] | integer | 2000–10000 |
questions[] | integer | required 10–5000, default 50 |
questions[] | 1 | | required default 1 |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string[] | required up to 50 items, default [] |
questions[] | string[] | required up to 20 items, default [] |
questions[] | "18-24" | | up to 6 items |
questions[] | "woman" | | up to 3 items |
questions[] | boolean | |
questions[] | object | |
questions[] | integer | required 1–5, default 1 |
questions[] | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
questions[] | boolean | required default false |
questions[] | "off" | | required default "off" |
questions[] | object | |
questions[] | number | required 0.5–0.95 |
questions[] | integer | required 5–5000 |
questions[] | "none" | | |
questions[] | string | up to 40 characters |
questions[] | 1 | | |
questions[] | object | |
questions[] | integer | required 1–10000 |
questions[] | integer | required 0–10000 |
questions[] | "heads" | | required default "heads" |
questions[] | 1 | | required default 7 |
questions[] | string | up to 40 characters |
questions[] | string | required |
questions[] | "draft" | | required |
questions[] | "app" | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | string[] | |
questions[] | boolean | |
questions[] | boolean | |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | |
questions[] | integer | | |
questions[] | integer | |
GET/v2/sets
Your sets, newest first.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
status | "open" | | |
limit | integer | 1–100 |
cursor | string |
| Field | Type | Notes |
|---|---|---|
sets | object[] | required |
sets[] | string | required |
sets[] | "open" | | required |
sets[] | string | | required |
sets[] | integer | required |
sets[] | 1 | | required |
sets[] | boolean | required |
sets[] | string | required |
sets[] | string[] | required |
sets[] | integer | required |
sets[] | integer | required |
sets[] | integer | required |
sets[] | object | | required |
sets[] | string | required |
sets[] | string | required |
sets[] | string | required |
sets[] | string | | required |
sets[] | integer | required |
sets[] | integer | required |
sets[] | string | | required |
sets[] | string | required |
sets[] | string | | required |
nextCursor | string | | required |
GET/v2/sets/{id}
A set and its questions in order.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
set | object | required |
set. | string | required |
set. | "open" | | required |
set. | string | | required |
set. | integer | required |
set. | 1 | | required |
set. | boolean | required |
set. | string | required |
set. | string[] | required |
set. | integer | required |
set. | integer | required |
set. | integer | required |
set. | object | | required |
set. | string | required |
set. | string | required |
set. | string | required |
set. | string | | required |
set. | integer | required |
set. | integer | required |
set. | string | | required |
set. | string | required |
set. | string | | required |
questions | object[] | required |
questions[] | "single_choice" | | required |
questions[] | string | required up to 600 characters |
questions[] | string | up to 120 characters |
questions[] | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
questions[] | object[] | required up to 8 items, default [] |
questions[] | string | required up to 40 characters |
questions[] | string (URL) | |
questions[] | string (URL)[] | up to 4 items |
questions[] | object | |
questions[] | string | required up to 24 characters |
questions[] | string | required up to 24 characters |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string (URL) | |
questions[] | string (URL) | |
questions[] | string | up to 120 characters |
questions[] | integer | 2000–10000 |
questions[] | integer | required 10–5000, default 50 |
questions[] | 1 | | required default 1 |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string[] | required up to 50 items, default [] |
questions[] | string[] | required up to 20 items, default [] |
questions[] | "18-24" | | up to 6 items |
questions[] | "woman" | | up to 3 items |
questions[] | boolean | |
questions[] | object | |
questions[] | integer | required 1–5, default 1 |
questions[] | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
questions[] | boolean | required default false |
questions[] | "off" | | required default "off" |
questions[] | object | |
questions[] | number | required 0.5–0.95 |
questions[] | integer | required 5–5000 |
questions[] | "none" | | |
questions[] | string | up to 40 characters |
questions[] | 1 | | |
questions[] | object | |
questions[] | integer | required 1–10000 |
questions[] | integer | required 0–10000 |
questions[] | "heads" | | required default "heads" |
questions[] | 1 | | required default 7 |
questions[] | string | up to 40 characters |
questions[] | string | required |
questions[] | "draft" | | required |
questions[] | "app" | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | string[] | |
questions[] | boolean | |
questions[] | boolean | |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | |
questions[] | integer | | |
questions[] | integer | |
POST/v2/sets/{id}/close
Close the set now: every open question closes with the answers it has and the unused reserve comes back.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
set | object | required |
set. | string | required |
set. | "open" | | required |
set. | string | | required |
set. | integer | required |
set. | 1 | | required |
set. | boolean | required |
set. | string | required |
set. | string[] | required |
set. | integer | required |
set. | integer | required |
set. | integer | required |
set. | object | | required |
set. | string | required |
set. | string | required |
set. | string | required |
set. | string | | required |
set. | integer | required |
set. | integer | required |
set. | string | | required |
set. | string | required |
set. | string | | required |
questions | object[] | required |
questions[] | "single_choice" | | required |
questions[] | string | required up to 600 characters |
questions[] | string | up to 120 characters |
questions[] | string | required pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
questions[] | object[] | required up to 8 items, default [] |
questions[] | string | required up to 40 characters |
questions[] | string (URL) | |
questions[] | string (URL)[] | up to 4 items |
questions[] | object | |
questions[] | string | required up to 24 characters |
questions[] | string | required up to 24 characters |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string (URL) | |
questions[] | string (URL) | |
questions[] | string | up to 120 characters |
questions[] | integer | 2000–10000 |
questions[] | integer | required 10–5000, default 50 |
questions[] | 1 | | required default 1 |
questions[] | boolean | required default false |
questions[] | object | |
questions[] | string[] | required up to 50 items, default [] |
questions[] | string[] | required up to 20 items, default [] |
questions[] | "18-24" | | up to 6 items |
questions[] | "woman" | | up to 3 items |
questions[] | boolean | |
questions[] | object | |
questions[] | integer | required 1–5, default 1 |
questions[] | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
questions[] | boolean | required default false |
questions[] | "off" | | required default "off" |
questions[] | object | |
questions[] | number | required 0.5–0.95 |
questions[] | integer | required 5–5000 |
questions[] | "none" | | |
questions[] | string | up to 40 characters |
questions[] | 1 | | |
questions[] | object | |
questions[] | integer | required 1–10000 |
questions[] | integer | required 0–10000 |
questions[] | "heads" | | required default "heads" |
questions[] | 1 | | required default 7 |
questions[] | string | up to 40 characters |
questions[] | string | required |
questions[] | "draft" | | required |
questions[] | "app" | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | | required |
questions[] | string | | |
questions[] | string[] | |
questions[] | boolean | |
questions[] | boolean | |
questions[] | string | | |
questions[] | object | | |
questions[] | string | required |
questions[] | string | required |
questions[] | string | required |
questions[] | string | | required |
questions[] | integer | required |
questions[] | integer | required |
questions[] | string | | |
questions[] | integer | | |
questions[] | integer | | |
refundCredits | integer | required |
GET/v2/sets/{id}/export.csv
Every accepted answer across the set as CSV: position, question, time, answer, visit (the random id grouping one browser's pass), answered_by and access.
API key or OAuth token with questions:read.
GET/v2/sets/{id}/export.jsonl
Every accepted answer across the set as JSON lines: position, question, options, answer, `choice`, each question's `cohortHash` and the visit.
API key or OAuth token with questions:read.
GET/v2/sets/{id}/link/qr.svg
The set link's QR code as SVG.
API key or OAuth token with questions:read.
GET/v2/sets/{id}/link/qr.png
The set link's QR code as a 1024-pixel PNG.
API key or OAuth token with questions:read.
Drafts and uploads
Save work in progress and upload images before you ask.
GET/v1/drafts
Saved drafts.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
drafts | object[] | required |
drafts[] | string | required |
drafts[] | object | required |
drafts[] | "single_choice" | | required |
drafts[] | string | up to 600 characters |
drafts[] | string | up to 120 characters |
drafts[] | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
drafts[] | object[] | up to 8 items, default [] |
drafts[] | object | |
drafts[] | boolean | default false |
drafts[] | object | |
drafts[] | integer | 10–5000, default 50 |
drafts[] | 1 | | default 1 |
drafts[] | boolean | default false |
drafts[] | object | |
drafts[] | object | |
drafts[] | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
drafts[] | boolean | default false |
drafts[] | "off" | | default "off" |
drafts[] | object | |
drafts[] | "none" | | |
drafts[] | string | up to 40 characters |
drafts[] | 1 | | |
drafts[] | object | |
drafts[] | "heads" | | default "heads" |
drafts[] | 1 | | default 7 |
drafts[] | string | up to 40 characters |
drafts[] | string | required |
drafts[] | "zapier_test" | |
POST/v1/drafts
Save a draft. PUT /v1/drafts/{id} updates one; DELETE removes it.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
type | "single_choice" | | required |
text | string | up to 600 characters |
context | string | up to 120 characters |
language | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
options | object[] | up to 8 items, default [] |
options[] | string | required up to 40 characters |
options[] | string (URL) | |
options[] | string (URL)[] | up to 4 items |
scaleLabels | object | |
scaleLabels. | string | required up to 24 characters |
scaleLabels. | string | required up to 24 characters |
neither | boolean | default false |
stimulus | object | |
stimulus. | string (URL) | |
stimulus. | string (URL) | |
stimulus. | string | up to 120 characters |
stimulus. | integer | 2000–10000 |
n | integer | 10–5000, default 50 |
tier | 1 | | default 1 |
rush | boolean | default false |
targeting | object | |
targeting. | string[] | up to 50 items, default [] |
targeting. | string[] | up to 20 items, default [] |
targeting. | "18-24" | | up to 6 items |
targeting. | "woman" | | up to 3 items |
targeting. | boolean | |
clickTest | object | |
clickTest. | integer | 1–5, default 1 |
scheduledFor | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
publicResults | boolean | default false |
reason | "off" | | default "off" |
goRule | object | |
goRule. | number | required 0.5–0.95 |
goRule. | integer | required 5–5000 |
contentFlag | "none" | | |
interestAudienceId | string | up to 40 characters |
minGrade | 1 | | |
interestPrice | object | |
interestPrice. | integer | required 1–10000 |
interestPrice. | integer | required 0–10000 |
answeredBy | "heads" | | default "heads" |
openForDays | 1 | | default 7 |
shownAs | string | up to 40 characters |
origin | "zapier_test" |
| Field | Type | Notes |
|---|---|---|
id | string | required |
draft | object | required |
draft. | "single_choice" | | required |
draft. | string | up to 600 characters |
draft. | string | up to 120 characters |
draft. | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
draft. | object[] | up to 8 items, default [] |
draft. | string | required up to 40 characters |
draft. | string (URL) | |
draft. | string (URL)[] | up to 4 items |
draft. | object | |
draft. | string | required up to 24 characters |
draft. | string | required up to 24 characters |
draft. | boolean | default false |
draft. | object | |
draft. | string (URL) | |
draft. | string (URL) | |
draft. | string | up to 120 characters |
draft. | integer | 2000–10000 |
draft. | integer | 10–5000, default 50 |
draft. | 1 | | default 1 |
draft. | boolean | default false |
draft. | object | |
draft. | string[] | required up to 50 items, default [] |
draft. | string[] | required up to 20 items, default [] |
draft. | "18-24" | | up to 6 items |
draft. | "woman" | | up to 3 items |
draft. | boolean | |
draft. | object | |
draft. | integer | required 1–5, default 1 |
draft. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
draft. | boolean | default false |
draft. | "off" | | default "off" |
draft. | object | |
draft. | number | required 0.5–0.95 |
draft. | integer | required 5–5000 |
draft. | "none" | | |
draft. | string | up to 40 characters |
draft. | 1 | | |
draft. | object | |
draft. | integer | required 1–10000 |
draft. | integer | required 0–10000 |
draft. | "heads" | | default "heads" |
draft. | 1 | | default 7 |
draft. | string | up to 40 characters |
updatedAt | string | required |
origin | "zapier_test" | |
PUT/v1/drafts/{id}
Replace a saved draft.
API key or OAuth token with questions:write.
404 not_found when the draft is not in the account the caller acts for.
| Field | Type | Notes |
|---|---|---|
type | "single_choice" | | required |
text | string | up to 600 characters |
context | string | up to 120 characters |
language | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
options | object[] | up to 8 items, default [] |
options[] | string | required up to 40 characters |
options[] | string (URL) | |
options[] | string (URL)[] | up to 4 items |
scaleLabels | object | |
scaleLabels. | string | required up to 24 characters |
scaleLabels. | string | required up to 24 characters |
neither | boolean | default false |
stimulus | object | |
stimulus. | string (URL) | |
stimulus. | string (URL) | |
stimulus. | string | up to 120 characters |
stimulus. | integer | 2000–10000 |
n | integer | 10–5000, default 50 |
tier | 1 | | default 1 |
rush | boolean | default false |
targeting | object | |
targeting. | string[] | up to 50 items, default [] |
targeting. | string[] | up to 20 items, default [] |
targeting. | "18-24" | | up to 6 items |
targeting. | "woman" | | up to 3 items |
targeting. | boolean | |
clickTest | object | |
clickTest. | integer | 1–5, default 1 |
scheduledFor | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
publicResults | boolean | default false |
reason | "off" | | default "off" |
goRule | object | |
goRule. | number | required 0.5–0.95 |
goRule. | integer | required 5–5000 |
contentFlag | "none" | | |
interestAudienceId | string | up to 40 characters |
minGrade | 1 | | |
interestPrice | object | |
interestPrice. | integer | required 1–10000 |
interestPrice. | integer | required 0–10000 |
answeredBy | "heads" | | default "heads" |
openForDays | 1 | | default 7 |
shownAs | string | up to 40 characters |
| Field | Type | Notes |
|---|---|---|
id | string | required |
draft | object | required |
draft. | "single_choice" | | required |
draft. | string | up to 600 characters |
draft. | string | up to 120 characters |
draft. | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
draft. | object[] | up to 8 items, default [] |
draft. | string | required up to 40 characters |
draft. | string (URL) | |
draft. | string (URL)[] | up to 4 items |
draft. | object | |
draft. | string | required up to 24 characters |
draft. | string | required up to 24 characters |
draft. | boolean | default false |
draft. | object | |
draft. | string (URL) | |
draft. | string (URL) | |
draft. | string | up to 120 characters |
draft. | integer | 2000–10000 |
draft. | integer | 10–5000, default 50 |
draft. | 1 | | default 1 |
draft. | boolean | default false |
draft. | object | |
draft. | string[] | required up to 50 items, default [] |
draft. | string[] | required up to 20 items, default [] |
draft. | "18-24" | | up to 6 items |
draft. | "woman" | | up to 3 items |
draft. | boolean | |
draft. | object | |
draft. | integer | required 1–5, default 1 |
draft. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
draft. | boolean | default false |
draft. | "off" | | default "off" |
draft. | object | |
draft. | number | required 0.5–0.95 |
draft. | integer | required 5–5000 |
draft. | "none" | | |
draft. | string | up to 40 characters |
draft. | 1 | | |
draft. | object | |
draft. | integer | required 1–10000 |
draft. | integer | required 0–10000 |
draft. | "heads" | | default "heads" |
draft. | 1 | | default 7 |
draft. | string | up to 40 characters |
updatedAt | string | required |
origin | "zapier_test" | |
DELETE/v1/drafts/{id}
Delete a saved draft.
API key or OAuth token with questions:write.
Deleting a draft that is already gone still answers { ok: true }.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
POST/v1/question-reviews
Start a background review of a draft's wording, or find the one already done.
API key or OAuth token with questions:write.
Advice only: it never spends and never changes the price. Returns at once with pending; ask again (GET) after retryMs. The same words are reviewed once a day, so calling it on every save is fine. skipped means there was nothing to review, with the reason in review.skippedReason. Each suggestion is one change to the draft (op) that you apply yourself; a tidy suggestion fixes capitals and spacing.
| Field | Type | Notes |
|---|---|---|
draft | object | required |
draft. | "single_choice" | | required |
draft. | string | required up to 600 characters |
draft. | string | up to 120 characters |
draft. | string | pattern ^[a-z]{2}(-[A-Z]{2})?$, default "en" |
draft. | object[] | up to 8 items, default [] |
draft. | string | required up to 40 characters |
draft. | string (URL) | |
draft. | string (URL)[] | up to 4 items |
draft. | object | |
draft. | string | required up to 24 characters |
draft. | string | required up to 24 characters |
draft. | boolean | default false |
draft. | object | |
draft. | string (URL) | |
draft. | string (URL) | |
draft. | string | up to 120 characters |
draft. | integer | 2000–10000 |
draft. | integer | 10–5000, default 50 |
draft. | 1 | | default 1 |
draft. | boolean | default false |
draft. | object | |
draft. | string[] | up to 50 items, default [] |
draft. | string[] | up to 20 items, default [] |
draft. | "18-24" | | up to 6 items |
draft. | "woman" | | up to 3 items |
draft. | boolean | |
draft. | object | |
draft. | integer | 1–5, default 1 |
draft. | string (date-time) | pattern ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z))$ |
draft. | boolean | default false |
draft. | "off" | | default "off" |
draft. | object | |
draft. | number | required 0.5–0.95 |
draft. | integer | required 5–5000 |
draft. | "none" | | |
draft. | string | up to 40 characters |
draft. | 1 | | |
draft. | object | |
draft. | integer | required 1–10000 |
draft. | integer | required 0–10000 |
draft. | "heads" | | default "heads" |
draft. | 1 | | default 7 |
draft. | string | up to 40 characters |
| Field | Type | Notes |
|---|---|---|
inputHash | string | required |
status | "pending" | | required |
review | object | |
review. | "ok" | | required |
review. | string | required |
review. | string | |
review. | string | |
review. | "pass" | | |
review. | object | |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | object[] | |
review. | string | required |
review. | "tidy" | | required |
review. | "info" | | required |
review. | string | required |
review. | string | required up to 180 characters |
review. | object | | |
review. | "flag_off" | | |
retryMs | integer |
GET/v1/question-reviews/{hash}
Where a draft's review stands: pending, ready, skipped or failed.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
inputHash | string | required |
status | "pending" | | required |
review | object | |
review. | "ok" | | required |
review. | string | required |
review. | string | |
review. | string | |
review. | "pass" | | |
review. | object | |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | integer | required 1–5 |
review. | object[] | |
review. | string | required |
review. | "tidy" | | required |
review. | "info" | | required |
review. | string | required |
review. | string | required up to 180 characters |
review. | object | | |
review. | "flag_off" | | |
retryMs | integer |
POST/v1/uploads
A pre-signed URL to upload an image or sound clip.
API key or OAuth token with questions:write.
PUT the file to uploadUrl with the returned headers (the URL is the credential, for 15 minutes), then use publicUrl in the question. Images are checked and their metadata stripped before heads see them.
| Field | Type | Notes |
|---|---|---|
kind | "image" | | required |
contentType | string | required |
bytes | integer | required |
| Field | Type | Notes |
|---|---|---|
uploadUrl | string | required |
publicUrl | string | required |
headers | map of string | required |
POST/v1/uploads/import
Copy an image from a public https link into 50heads.
API key or OAuth token with questions:write.
The image is fetched on our side (public https hosts only, three redirects at most), checked like an upload and stored. JPEG, PNG or WebP up to 5 MB.
| Field | Type | Notes |
|---|---|---|
url | string (URL) | required |
| Field | Type | Notes |
|---|---|---|
publicUrl | string | required |
width | integer | | required |
height | integer | | required |
POST/v1/mockups
Draw a store listing or search result mockup from your details.
API key or OAuth token with questions:write.
A listing or a search result in 50heads styling (never a marketplace's), 1200 × 1600, drawn from a title, a price, a rating, a review count and your image, then stored like an upload. Use imageUrl on an option or the stimulus within 15 minutes. See docs/specs/mockups.md.
| Field | Type | Notes |
|---|---|---|
kind | "listing" | | required |
title | string | required up to 120 characters |
price | object | required |
price. | number | required 0–1000000 |
price. | "GBP" | | required |
rating | number | 0–5 |
reviews | integer | 0–100000000 |
imageUrl | string (URL) | required |
line | string | up to 40 characters |
| Field | Type | Notes |
|---|---|---|
kind | "listing" | | required |
imageUrl | string | required |
width | integer | required |
height | integer | required |
expiresAt | string | required |
Projects
Group questions into projects in the account the key belongs to (yours or a team's). Label, archive and give each question your own reference with the question routes.
GET/v1/projects
Projects in use, or the archived ones.
API key or OAuth token with questions:read.
| Field | Type | Notes |
|---|---|---|
archived | boolean |
| Field | Type | Notes |
|---|---|---|
projects | object[] | required |
projects[] | string | required |
projects[] | string | required |
projects[] | string | | required |
projects[] | string | | required |
projects[] | boolean | required |
projects[] | boolean | required |
projects[] | string | | |
projects[] | integer | required |
projects[] | string | required |
projects[] | string | required |
POST/v1/projects
Make a project.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
name | string | required up to 80 characters |
description | string | | |
goal | string | |
| Field | Type | Notes |
|---|---|---|
project | object | required |
project. | string | required |
project. | string | required |
project. | string | | required |
project. | string | | required |
project. | boolean | required |
project. | boolean | required |
project. | string | | |
project. | integer | required |
project. | string | required |
project. | string | required |
PATCH/v1/projects/{id}
Rename, bookmark or archive a project.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
name | string | up to 80 characters |
description | string | | |
goal | string | | |
bookmarked | boolean | |
archived | boolean | |
costCenter | string | |
| Field | Type | Notes |
|---|---|---|
project | object | required |
project. | string | required |
project. | string | required |
project. | string | | required |
project. | string | | required |
project. | boolean | required |
project. | boolean | required |
project. | string | | |
project. | integer | required |
project. | string | required |
project. | string | required |
DELETE/v1/projects/{id}
Delete a project. Its questions stay, outside any project.
API key or OAuth token with questions:write.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
Audiences
Panels of heads who proved they fit something (UK commuter cyclists, for example). Ask one by putting its id in a draft's `interestAudienceId`, with a `minGrade`: it replaces targeting, and the price per answer is the audience's at that grade.
GET/v1/interest-audiences
Audiences you can ask, with their size band and price per answer by grade.
No authentication.
open=1 keeps only audiences open to join from the caller's country. With a key and mine=asking, private audiences your team sponsors are listed too. Sizes are bands, never counts.
| Field | Type | Notes |
|---|---|---|
q | string | up to 60 characters |
country | string | pattern ^[A-Z]{2}$ |
lang | string | up to 5 characters |
category | "outdoors" | | |
open | "0" | | |
mine | "asking" |
| Field | Type | Notes |
|---|---|---|
audiences | object[] | required |
audiences[] | string | required |
audiences[] | string | required |
audiences[] | string | required |
audiences[] | string | required |
audiences[] | string | | required |
audiences[] | "draft" | | required |
audiences[] | string | required |
audiences[] | string[] | required |
audiences[] | string[] | required |
audiences[] | "under_50" | | required |
audiences[] | object | required |
audiences[] | integer | required |
audiences[] | integer | required |
audiences[] | integer | required |
audiences[] | integer | required |
audiences[] | integer | required |
audiences[] | boolean | required |
audiences[] | boolean | required |
audiences[] | string | | required |
GET/v1/interest-audiences/{slug}
One audience: what it is, the tags it stamps, grades and pay.
No authentication.
| Field | Type | Notes |
|---|---|---|
audience | object | required |
audience. | string | required |
audience. | string | required |
audience. | string | required |
audience. | string[] | required |
audience. | string | required |
audience. | string | | required |
audience. | "draft" | | required |
audience. | string[] | required |
audience. | string[] | required |
audience. | object[] | required |
audience. | string | required |
audience. | string | required |
audience. | object[] | required |
audience. | 1 | | required |
audience. | string | required |
audience. | integer | required |
audience. | integer | required |
audience. | "quiz" | | required |
audience. | "under_50" | | required |
audience. | string | | required |
audience. | boolean | required |
audience. | object | required |
audience. | integer | required |
audience. | integer | required |
audience. | integer | required |
audience. | string[] | required |
Saved audiences
A targeting setup you reuse: how many heads, tier, rush, language and who to ask, saved under a name in the account the caller acts for (yours or a team's). They are for the portal and the app composer, so these routes need a signed-in person; API keys and connected apps get 403 `session_required`. To ask the same audience from a key, send the same fields in the draft.
GET/v1/audiences
Saved audiences in the account.
Portal session only.
A person signed in at 50heads.com or in the app. Keys and connected apps get 403 session_required.
| Field | Type | Notes |
|---|---|---|
audiences | object[] | required |
audiences[] | string | required |
audiences[] | string | required up to 60 characters |
audiences[] | integer | required 10–5000 |
audiences[] | 1 | | required |
audiences[] | boolean | required |
audiences[] | string | required |
audiences[] | object | required |
audiences[] | string[] | required up to 50 items, default [] |
audiences[] | string[] | required up to 20 items, default [] |
audiences[] | "18-24" | | up to 6 items |
audiences[] | "woman" | | up to 3 items |
audiences[] | boolean |
POST/v1/audiences
Save an audience under a name.
Portal session only.
A person signed in. Team members who can ask can save for the team. At most 50 per account: 409 too_many_audiences after that.
| Field | Type | Notes |
|---|---|---|
name | string | required up to 60 characters |
n | integer | required 10–5000 |
tier | 1 | | required |
rush | boolean | required |
language | string | required |
targeting | object | required |
targeting. | string[] | up to 50 items, default [] |
targeting. | string[] | up to 20 items, default [] |
targeting. | "18-24" | | up to 6 items |
targeting. | "woman" | | up to 3 items |
targeting. | boolean |
| Field | Type | Notes |
|---|---|---|
audience | object | required |
audience. | string | required |
audience. | string | required up to 60 characters |
audience. | integer | required 10–5000 |
audience. | 1 | | required |
audience. | boolean | required |
audience. | string | required |
audience. | object | required |
audience. | string[] | required up to 50 items, default [] |
audience. | string[] | required up to 20 items, default [] |
audience. | "18-24" | | up to 6 items |
audience. | "woman" | | up to 3 items |
audience. | boolean |
PUT/v1/audiences/{id}
Replace a saved audience.
Portal session only.
| Field | Type | Notes |
|---|---|---|
name | string | required up to 60 characters |
n | integer | required 10–5000 |
tier | 1 | | required |
rush | boolean | required |
language | string | required |
targeting | object | required |
targeting. | string[] | up to 50 items, default [] |
targeting. | string[] | up to 20 items, default [] |
targeting. | "18-24" | | up to 6 items |
targeting. | "woman" | | up to 3 items |
targeting. | boolean |
| Field | Type | Notes |
|---|---|---|
audience | object | required |
audience. | string | required |
audience. | string | required up to 60 characters |
audience. | integer | required 10–5000 |
audience. | 1 | | required |
audience. | boolean | required |
audience. | string | required |
audience. | object | required |
audience. | string[] | required up to 50 items, default [] |
audience. | string[] | required up to 20 items, default [] |
audience. | "18-24" | | up to 6 items |
audience. | "woman" | | up to 3 items |
audience. | boolean |
DELETE/v1/audiences/{id}
Delete a saved audience.
Portal session only.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
Credits and account
Balance, ledger, invoices and statements. Credits are bought on the web; the API spends them.
GET/v1/billing/balance
Credits, what is reserved by live questions, and what is left under this key's daily cap.
API key or OAuth token with account:read.
| Field | Type | Notes |
|---|---|---|
credits | integer | required |
reserved | integer | required |
expiring | object[] | required |
expiring[] | integer | required |
expiring[] | string | required |
currency | "GBP" | | required |
capRemaining | integer | | required |
freeQuestionToday | boolean | required |
privateDeclaredAt | string | | |
privateFreeAnswersLeft | integer |
GET/v1/billing/ledger
Every credit movement, newest first.
API key or OAuth token with account:read.
| Field | Type | Notes |
|---|---|---|
cursor | string |
| Field | Type | Notes |
|---|---|---|
rows | object[] | required |
rows[] | string | required |
rows[] | string | required |
rows[] | "purchase" | | required |
rows[] | string | required |
rows[] | "pending" | | required |
rows[] | integer | required |
rows[] | string | | required |
rows[] | object | | |
rows[] | string | required |
rows[] | "rejected" | | required |
rows[] | "too_fast" | | required |
rows[] | integer | required |
rows[] | "not_paid" | | required |
rows[] | string | | required |
rows[] | string | | required |
rows[] | string | | |
rows[] | "web" | | |
rows[] | string | | |
nextCursor | string | | required |
POST/v1/billing/checkout
Start a card or bank-transfer purchase (portal session only).
Portal session only.
Not available to API keys: buying credits needs a signed-in person.
| Field | Type | Notes |
|---|---|---|
pack | string | required |
currency | "GBP" | | required |
method | "card" | | required |
returnPath | string | pattern ^\/app(\/[\w\-/]*)?$ |
POST/v1/billing/store-purchases/intent
Start an App Store or Google Play credit-pack purchase. Returns the account token to pass to the store.
Portal session only.
The app sends appAccountToken to StoreKit and obfuscatedAccountId to Play Billing. Credits are granted by storePurchase after the store returns a signed transaction or purchase token.
| Field | Type | Notes |
|---|---|---|
store | "apple" | | required |
| Field | Type | Notes |
|---|---|---|
appAccountToken | string | required |
obfuscatedAccountId | string | required |
POST/v1/billing/store-purchases
Verify an App Store or Google Play credit-pack purchase and grant the credits once.
Portal session only.
Apple: signedTransaction is the StoreKit 2 JWS. Google: purchaseToken is checked with the Play Developer API, then consumed. A repeat of the same transaction returns status duplicate and does not grant again. Finish the store transaction only after this succeeds. The stores are the merchant of record, so this does not create a VAT invoice.
| Field | Type | Notes |
|---|---|---|
store | "apple" | | required |
productId | string | required |
signedTransaction | string | at least 20 characters |
purchaseToken | string | at least 8 characters |
| Field | Type | Notes |
|---|---|---|
status | "granted" | | required |
credits | integer | required |
transactionId | string | required |
productId | string | required |
balance | integer | required |
testPurchase | boolean |
GET/v1/billing/store-purchases
Recent App Store and Google Play credit-pack purchases on the account, newest first.
Portal session only.
Each purchase has the credits added, when, its state (granted or refunded) and the receipt currency and price in minor units. Currency and price are null where the store's receipt does not state them (Google Play). Test purchases that added no credits are left out.
| Field | Type | Notes |
|---|---|---|
purchases | object[] | required |
purchases[] | string | required |
purchases[] | "apple" | | required |
purchases[] | string | required |
purchases[] | integer | required |
purchases[] | "granted" | | required |
purchases[] | string | required |
purchases[] | string | | required |
purchases[] | string | | required |
purchases[] | integer | | required |
purchases[] | string | required |
GET/v1/billing/invoices
Invoices, credit notes and self-billing statements, newest first.
API key or OAuth token with account:read.
Each has a pdfUrl on this API; fetch it with the same key.
| Field | Type | Notes |
|---|---|---|
invoices | object[] | required |
invoices[] | string | required |
invoices[] | string | required |
invoices[] | "invoice" | | required |
invoices[] | string | required |
invoices[] | string | required |
invoices[] | number | required |
invoices[] | number | required |
invoices[] | number | required |
invoices[] | "uk_standard" | | required |
invoices[] | string | required |
GET/v1/billing/invoices/{id}/pdf
An invoice or credit note as a PDF.
API key or OAuth token with account:read.
GET/v1/billing/profile
The legal name, address and VAT number printed on invoices.
API key or OAuth token with account:read.
Changing it (PUT) needs a signed-in person.
| Field | Type | Notes |
|---|---|---|
legalName | string | | required |
address | string | | required |
country | string | | required |
vatNumber | string | | required |
vatValid | boolean | | required |
GET/v1/billing/statements
Monthly and annual credit statements.
API key or OAuth token with account:read.
| Field | Type | Notes |
|---|---|---|
statements | object[] | required |
statements[] | string | required |
statements[] | string | required |
statements[] | "monthly" | | required |
statements[] | integer | required |
statements[] | string | required |
statements[] | string | |
GET/v1/billing/statements/{id}/{format}
One statement as a PDF, or as CSV (`format` is `pdf` or `csv`).
API key or OAuth token with account:read.
format csv answers text/csv instead.
GET/v1/billing/transfers
Bank transfers waiting for the money to arrive, or matched.
API key or OAuth token with account:read.
| Field | Type | Notes |
|---|---|---|
transfers | object[] | required |
transfers[] | string | required |
transfers[] | string | required |
transfers[] | integer | required |
transfers[] | number | required |
transfers[] | "GBP" | | required |
transfers[] | "awaiting" | | required |
transfers[] | string | required |
transfers[] | string | required |
GET/v1/billing/invoice-terms
Whether you have 14-day invoice terms for the larger packs.
API key or OAuth token with account:read.
Asking for terms (POST) needs a signed-in person.
| Field | Type | Notes |
|---|---|---|
status | "none" | | required |
termsDays | integer | | required |
decidedAt | string | | required |
purchaseOrder | string | | |
billingContactName | string | | |
billingContactEmail | string | |
GET/v1/billing/disputes
Disputes you opened on questions, and how they ended.
API key or OAuth token with account:read.
| Field | Type | Notes |
|---|---|---|
disputes | object[] | required |
disputes[] | string | required |
disputes[] | string | required |
disputes[] | string | required |
disputes[] | string | required |
disputes[] | "open" | | required |
disputes[] | integer | required |
disputes[] | string | | required |
disputes[] | string | required |
disputes[] | string | | required |
GET/v1/billing/packs
The credit packs on sale and their price in a currency.
No authentication.
| Field | Type | Notes |
|---|---|---|
currency | string |
| Field | Type | Notes |
|---|---|---|
packs | object[] | required |
packs[] | string | required |
packs[] | integer | required |
packs[] | integer | required |
packs[] | number | required |
packs[] | string | required |
packs[] | boolean | required |
GET/v1/me
The account behind the key: name, tier, languages, credits and sign-in providers.
API key or OAuth token with account:read.
| Field | Type | Notes |
|---|---|---|
user | object | required |
user. | string | required |
user. | string (email) | required pattern ^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$ |
user. | string | | required |
user. | 0 | | required |
user. | string | | required |
user. | string | | required |
user. | "GBP" | | required |
user. | "en" | | required |
user. | string | | required |
user. | integer | required |
user. | integer | required |
user. | integer | required |
user. | "apple" | | required |
user. | string | required |
user. | boolean | |
user. | boolean | |
user. | boolean |
GET/v1/connections/current
The connection behind this key or token: its scopes, its caps and what it has spent today and this month.
API key or OAuth token.
Any key or token can read its own; no scope is needed. This is what MCP balance uses to show an agent its cap. 404 not_found for a first-party session, which has no connection.
| Field | Type | Notes |
|---|---|---|
connection | object | required |
connection. | string | required |
connection. | "oauth" | | required |
connection. | string | | required |
connection. | string | required |
connection. | string | | required |
connection. | "questions:read" | | required |
connection. | integer | required |
connection. | integer | required |
connection. | integer | required |
connection. | string | | required |
connection. | boolean | | required |
connection. | string | required |
connection. | string | | required |
connection. | integer | | |
connection. | integer | | |
connection. | string | |
POST/v1/connections/calls
Report tool calls made on this connection, for the usage and logs on the Developers page.
API key or OAuth token.
Used by the MCP server. Never send question text; calls are kept 90 days. 400 no_connection when the caller has no connection.
| Field | Type | Notes |
|---|---|---|
calls | object[] | required up to 100 items |
calls[] | string | required up to 64 characters |
calls[] | string | | |
calls[] | string | | |
calls[] | "ok" | | required |
calls[] | string | | |
calls[] | integer | required 0–3600000 |
calls[] | string | required up to 64 characters |
calls[] | string | | |
calls[] | integer | ≥ 0 |
calls[] | boolean | |
host | string | up to 100 characters |
protocolVersion | string | up to 20 characters |
validatesIss | boolean |
| Field | Type | Notes |
|---|---|---|
ok | true | required |
Support
Open a ticket from a script or an agent. Replies come by email and in the portal.
POST/v1/support/tickets
Open a support ticket.
API key or OAuth token.
Signed in (key, OAuth or session), the reply goes to the account's email. Without a token, send email. 10 tickets an hour.
| Field | Type | Notes |
|---|---|---|
subject | string | required up to 140 characters, at least 3 characters |
body | string | required up to 5000 characters, at least 10 characters |
appVersion | string | up to 40 characters |
category | "payout" | | |
email | string (email) | pattern ^(?:[A-Za-z0-9_'+\-]+\.)*[A-Za-z0-9_'+\-]*[A-Za-z0-9_+-]@(?:[A-Za-z0-9][A-Za-z0-9\-]*\.)+[A-Za-z]{2,}$ |
locale | string | up to 10 characters |
website | string | up to 2000 characters |
openedAt | integer | ≥ 0 |
| Field | Type | Notes |
|---|---|---|
ticketId | string | required |
Webhook endpoints
Get an HTTPS POST when something happens, instead of polling. Manage endpoints in the portal under Developers, or with a key or OAuth grant that has webhooks:read (list) and webhooks:write (change). Keys made before scopes cannot manage webhooks.
GET/v1/webhooks/schemas
The JSON Schema of every event's data, and the payload versions.
No authentication.
Payloads are additive inside a version: new optional fields may appear; existing fields never change meaning or disappear.
| Field | Type | Notes |
|---|---|---|
apiVersions | "2026-10-10"[] | required |
latest | "2026-10-10" | required |
events | object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
events. | map of object | required |
GET/v1/webhooks/events
The latest events of one type in this account, newest first, as deliveries carry them.
API key or OAuth token with webhooks:read.
Each event is the exact body a delivery sends (id, type, createdAt, apiVersion, data), so a receiver can use one as sample data or poll with it and drop ids it has seen. Events are kept whether or not an endpoint listens, for 90 days. A personal account lists the person's events, including their asks in a team; a team lists the team's. A key acts for its own account (personal or team); a session acts for the account in the account header. Team members who can ask can read; the owner and admins can change.
| Field | Type | Notes |
|---|---|---|
type | "question.reserved" | | required |
limit | integer | 1–25, default 3 |
| Field | Type | Notes |
|---|---|---|
events | object[] | required |
events[] | string | required |
events[] | string | required |
events[] | string | required |
events[] | "2026-10-10" | |
events[] | map of object | required |
GET/v1/webhooks/endpoints
The endpoints in this account (yours, or the team's). Secrets are masked.
API key or OAuth token with webhooks:read.
A key acts for its own account (personal or team); a session acts for the account in the account header. Team members who can ask can read; the owner and admins can change.
| Field | Type | Notes |
|---|---|---|
endpoints | object[] | required |
endpoints[] | string | required |
endpoints[] | string (URL) | required |
endpoints[] | "question.reserved" | | required |
endpoints[] | string | required |
endpoints[] | string | required |
endpoints[] | string | | required |
endpoints[] | integer | | required |
endpoints[] | string | | |
endpoints[] | boolean | |
endpoints[] | string | | |
endpoints[] | string | | |
endpoints[] | string | | |
endpoints[] | string | | |
endpoints[] | "2026-10-10" | |
endpoints[] | object | | |
endpoints[] | string[] | up to 20 items |
endpoints[] | string[] | up to 20 items |
endpoints[] | object | | |
endpoints[] | string | required |
endpoints[] | string | required |
POST/v1/webhooks/endpoints
Add an endpoint. The signing secret is in the response, once.
API key or OAuth token with webhooks:write.
https only, public hosts only. Up to 10 endpoints on a personal account and 100 on a team. In a team, only the owner or an admin can add one. apiVersion defaults to the latest. An endpoint made with a key or OAuth grant is deleted when that key or grant is revoked. Zapier's REST hooks count against its connection (up to 50 each), not the account's limit.
| Field | Type | Notes |
|---|---|---|
url | string (URL) | required up to 500 characters |
events | "question.reserved" | | required |
description | string | up to 100 characters |
filter | object | |
filter. | string[] | up to 20 items |
filter. | string[] | up to 20 items |
apiVersion | "2026-10-10" |
| Field | Type | Notes |
|---|---|---|
endpoint | object | required |
endpoint. | string | required |
endpoint. | string (URL) | required |
endpoint. | "question.reserved" | | required |
endpoint. | string | required |
endpoint. | string | required |
endpoint. | string | | required |
endpoint. | integer | | required |
endpoint. | string | | |
endpoint. | boolean | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | "2026-10-10" | |
endpoint. | object | | |
endpoint. | string[] | up to 20 items |
endpoint. | string[] | up to 20 items |
endpoint. | object | | |
endpoint. | string | required |
endpoint. | string | required |
PATCH/v1/webhooks/endpoints/{endpointId}
Change an endpoint's address, events, description or filter, or pause and resume it.
API key or OAuth token with webhooks:write.
filter: null clears the filter. enabled: true resumes an endpoint that was switched off after failures.
| Field | Type | Notes |
|---|---|---|
url | string (URL) | up to 500 characters |
events | "question.reserved" | | |
description | string | | |
enabled | boolean | |
filter | object | | |
filter. | string[] | up to 20 items |
filter. | string[] | up to 20 items |
| Field | Type | Notes |
|---|---|---|
endpoint | object | required |
endpoint. | string | required |
endpoint. | string (URL) | required |
endpoint. | "question.reserved" | | required |
endpoint. | string | required |
endpoint. | string | required |
endpoint. | string | | required |
endpoint. | integer | | required |
endpoint. | string | | |
endpoint. | boolean | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | "2026-10-10" | |
endpoint. | object | | |
endpoint. | string[] | up to 20 items |
endpoint. | string[] | up to 20 items |
endpoint. | object | | |
endpoint. | string | required |
endpoint. | string | required |
DELETE/v1/webhooks/endpoints/{endpointId}
Delete an endpoint. Nothing more is sent to it.
API key or OAuth token with webhooks:write.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
POST/v1/webhooks/endpoints/{endpointId}/rotate-secret
A new signing secret, shown once. The old one keeps signing for the overlap.
API key or OAuth token with webhooks:write.
overlapHours defaults to 24 (0 to 168). During the overlap every delivery carries a signature from each secret; previousSecret.expiresAt says when the old one stops. 0 cuts over at once.
| Field | Type | Notes |
|---|---|---|
overlapHours | integer | 0–168, default 24 |
| Field | Type | Notes |
|---|---|---|
endpoint | object | required |
endpoint. | string | required |
endpoint. | string (URL) | required |
endpoint. | "question.reserved" | | required |
endpoint. | string | required |
endpoint. | string | required |
endpoint. | string | | required |
endpoint. | integer | | required |
endpoint. | string | | |
endpoint. | boolean | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | string | | |
endpoint. | "2026-10-10" | |
endpoint. | object | | |
endpoint. | string[] | up to 20 items |
endpoint. | string[] | up to 20 items |
endpoint. | object | | |
endpoint. | string | required |
endpoint. | string | required |
POST/v1/webhooks/endpoints/{endpointId}/test
Send a signed webhook.test event to this endpoint now.
API key or OAuth token with webhooks:write.
Signed and logged like any other delivery, and retried the same way if it fails.
| Field | Type | Notes |
|---|---|---|
outcome | "succeeded" | | required |
delivery | object | required |
delivery. | string | required |
delivery. | string | required |
delivery. | "question.reserved" | | required |
delivery. | integer | | required |
delivery. | integer | required |
delivery. | string | | required |
delivery. | string | required |
delivery. | string | |
delivery. | "pending" | | |
delivery. | string | | |
delivery. | string | | |
delivery. | string | |
GET/v1/webhooks/deliveries
The latest 100 deliveries, newest first.
API key or OAuth token with webhooks:read.
| Field | Type | Notes |
|---|---|---|
endpointId | string | |
state | "pending" | |
| Field | Type | Notes |
|---|---|---|
deliveries | object[] | required |
deliveries[] | string | required |
deliveries[] | string | required |
deliveries[] | "question.reserved" | | required |
deliveries[] | integer | | required |
deliveries[] | integer | required |
deliveries[] | string | | required |
deliveries[] | string | required |
deliveries[] | string | |
deliveries[] | "pending" | | |
deliveries[] | string | | |
deliveries[] | string | | |
deliveries[] | string | |
GET/v1/webhooks/deliveries/{deliveryId}/attempts
Each attempt at one delivery: status, error and time taken.
API key or OAuth token with webhooks:read.
| Field | Type | Notes |
|---|---|---|
attempts | object[] | required |
attempts[] | integer | required |
attempts[] | integer | | required |
attempts[] | string | | required |
attempts[] | integer | required |
attempts[] | string | required |
POST/v1/webhooks/deliveries/{deliveryId}/replay
Send a delivery's event again, as a new delivery.
API key or OAuth token with webhooks:write.
The body and webhook-id are the original event's, so a receiver that keeps event ids ignores a duplicate. Signed with the endpoint's current secrets.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
deliveryId | string | required |
A2A push notifications
The Agent2Agent (A2A) server at https://mcp.50heads.com/a2a stores the push notification configs its peers set on a task here, and you can manage them with a key too. A task id is the question id. Each config gets a POST for every change of state, signed with its token. Reads need webhooks:read, changes webhooks:write, and both questions:read. Being introduced: 404 `not_found` until A2A is on for your account.
GET/v1/a2a/status
Whether the A2A server is on for anyone.
No authentication.
The agent card is at https://mcp.50heads.com/.well-known/agent-card.json while this is true.
| Field | Type | Notes |
|---|---|---|
enabled | boolean | required |
GET/v1/a2a/access
Whether the A2A server is on for the caller.
API key or OAuth token.
| Field | Type | Notes |
|---|---|---|
enabled | boolean | required |
GET/v1/a2a/tasks/{taskId}/push-configs
Your push notification configs on a task.
API key or OAuth token with webhooks:read.
Also needs questions:read. A task in another account is 404 not_found.
| Field | Type | Notes |
|---|---|---|
configs | object[] | required |
configs[] | string | required |
configs[] | string | required |
configs[] | string | required |
configs[] | string | required |
configs[] | string | required |
configs[] | object | | required |
configs[] | string | required |
configs[] | "1.0" | | required |
configs[] | string | required |
POST/v1/a2a/tasks/{taskId}/push-configs
Send a task's changes of state to a URL.
API key or OAuth token with webhooks:write.
Also needs questions:read. https on a public host. Up to 5 configs on a task; the same id again replaces yours. Each push carries Authorization: <scheme> <credentials> when you set authentication, X-A2A-Notification-Token: <token>, and Standard Webhooks headers signed with the secret whsec_ + base64(token), so you verify it with the token alone. protocolVersion 1.0 sends a StreamResponse with a statusUpdate (application/a2a+json); 0.3 sends the Task. Call GetTask (or GET /v2/questions/{id}/result) for the results.
| Field | Type | Notes |
|---|---|---|
id | string | pattern ^[A-Za-z0-9._:-]{1,64}$ |
url | string | required up to 2000 characters |
token | string | up to 512 characters, at least 16 characters |
authentication | object | |
authentication. | string | required up to 40 characters, pattern ^[A-Za-z][A-Za-z0-9!#$%&'*+.^_`|~-]*$ |
authentication. | string | up to 4096 characters |
protocolVersion | "1.0" | | default "1.0" |
| Field | Type | Notes |
|---|---|---|
config | object | required |
config. | string | required |
config. | string | required |
config. | string | required |
config. | string | required |
config. | string | required |
config. | object | | required |
config. | string | required |
config. | "1.0" | | required |
config. | string | required |
GET/v1/a2a/tasks/{taskId}/push-configs/{configId}
One of your push notification configs on a task.
API key or OAuth token with webhooks:read.
Also needs questions:read. Credentials are never returned; the token is.
| Field | Type | Notes |
|---|---|---|
config | object | required |
config. | string | required |
config. | string | required |
config. | string | required |
config. | string | required |
config. | string | required |
config. | object | | required |
config. | string | required |
config. | "1.0" | | required |
config. | string | required |
DELETE/v1/a2a/tasks/{taskId}/push-configs/{configId}
Stop a push notification config. Nothing more is sent to it.
API key or OAuth token with webhooks:write.
Also needs questions:read. Deleting one that is already gone answers ok.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
Workspace apps
Ask from Slack, Microsoft Teams, Jira, Linear or Zapier. Install 50heads into a Slack workspace, a Jira site or a Linear workspace from the portal under Settings, Integrations; asks from it spend this account's credits up to a daily cap. In Jira and Linear, a comment that starts with `/50heads ask` asks from the issue, and the results come back to the issue as a comment. Zapier connects with OAuth like any other app and is listed beside the Slack installs. List apps with apps:read; change the cap or remove one with apps:write.
GET/v1/apps
The workspace apps installed in this account (yours, or the team's), and its Zapier connections, with today's spend.
API key or OAuth token with apps:read.
Keys made before scopes cannot list apps. In a team, any role that can ask may list them. zapier lists live Zapier connections with their daily cap, today's spend and live REST hooks; removing one in the portal revokes the connection and deletes its hooks.
| Field | Type | Notes |
|---|---|---|
apps | object[] | required |
apps[] | string | required |
apps[] | "slack" | | required |
apps[] | string | required |
apps[] | string | required |
apps[] | string | | required |
apps[] | integer | required |
apps[] | integer | required |
apps[] | string | required |
apps[] | object | required |
apps[] | string | | required |
apps[] | string | | required |
apps[] | "active" | | required |
zapier | object[] | required default [] |
zapier[] | string | required |
zapier[] | string | required |
zapier[] | string | | required |
zapier[] | integer | required |
zapier[] | integer | required |
zapier[] | integer | required |
zapier[] | object | required |
zapier[] | string | | required |
zapier[] | string | | required |
teamsAvailable | boolean | required default false |
jiraAvailable | boolean | required default false |
linearAvailable | boolean | required default false |
GET/v1/apps/slack/install
Slack's authorize page, with a signed state that works once, for 10 minutes.
Portal session only.
Portal session only; in a team, the owner or an admin. Slack sends the person back to the portal's Integrations page with installed=slack, or error= denied, expired, already_installed or failed. 503 slack_not_configured when Slack is not set up.
| Field | Type | Notes |
|---|---|---|
url | string | required |
GET/v1/apps/jira/install
Atlassian's authorize page for the 50heads Jira app, with a signed state that works once, for 10 minutes.
Portal session only.
Portal session only; in a team, the owner or an admin. Atlassian sends the person back to the portal's Integrations page with installed=jira, or error= denied, expired, already_installed or failed. One Jira site per install. 503 jira_not_configured when the Atlassian app is not set up; 404 while the Jira app is off on this server.
| Field | Type | Notes |
|---|---|---|
url | string | required |
GET/v1/apps/linear/install
Linear's authorize page for the 50heads Linear app, with a signed state that works once, for 10 minutes.
Portal session only.
Portal session only; in a team, the owner or an admin. Linear sends the person back to the portal's Integrations page with installed=linear, or error= denied, expired, already_installed or failed. 503 linear_not_configured when the Linear app is not set up; 404 while the Linear app is off on this server.
| Field | Type | Notes |
|---|---|---|
url | string | required |
PATCH/v1/apps/{appId}
Change an app's daily cap, in credits.
API key or OAuth token with apps:write.
In a team, the owner or an admin. Asks over the cap are refused with spend_cap_reached.
| Field | Type | Notes |
|---|---|---|
capDailyPence | integer | 100–10000000 |
| Field | Type | Notes |
|---|---|---|
app | object | required |
app. | string | required |
app. | "slack" | | required |
app. | string | required |
app. | string | required |
app. | string | | required |
app. | integer | required |
app. | integer | required |
app. | string | required |
app. | object | required |
app. | string | | required |
app. | string | | required |
app. | "active" | | required |
DELETE/v1/apps/{appId}
Uninstall: revokes the workspace's token and the app's connection.
API key or OAuth token with apps:write.
Questions already asked keep running and are refunded as usual if they underfill; their results cards are not posted.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
Event stream and warehouse export
Every event webhooks deliver, as a stream you page through: oldest first by `updatedAt`, with a cursor that never skips or repeats an event, so a scheduled job or an ELT tool (Airbyte, Fivetran, Hevo) reads only what is new. Read the account's stream with events:read; an organization admin reads every workspace's at /v1/organizations/current/events. Organizations can also have it, and their audit trail, written to their own S3, R2 or Google Cloud Storage bucket as JSON lines on a schedule, with a manifest per run (Organization settings, Warehouse export). Being introduced: 404 `not_found` until it is on for your account.
GET/v1/events
The account's events, oldest first by updatedAt, paged by a stable cursor.
API key or OAuth token with events:read.
A key acts for its own account; a session for the account in the account header. A personal account reads its own events (not its teams'); a team reads the team's. Keys made before scopes cannot read it (403 insufficient_scope). The page is oldest first by updatedAt, then sequence. nextCursor is always set: pass it back for the next page, or keep it and poll; an empty page still moves it on, so the next call reads only new events. Events are the webhook catalog's, with the same data; they are kept 90 days. Load by id to drop the rare repeat. Behind the warehouseExport flag: 404 not_found until it is on for your account.
| Field | Type | Notes |
|---|---|---|
cursor | string | up to 40 characters |
since | string | up to 40 characters |
type | string | up to 60 characters, pattern ^[a-z_]+(\.[a-z_]+)?$ |
limit | integer | 1–500 |
| Field | Type | Notes |
|---|---|---|
events | object[] | required |
events[] | string | required |
events[] | string | required |
events[] | integer | required |
events[] | string | required |
events[] | string | required |
events[] | string | | required |
events[] | map of object | required |
nextCursor | string | required |
hasMore | boolean | required |
GET/v1/organizations/current/events
Every workspace's events in the organization, oldest first by updatedAt, paged by a stable cursor.
API key or OAuth token with events:read.
Organization admins only (403 organization_admin_required); API keys, connected apps and service accounts with events:read where the organization has machine identities (otherwise 403 session_required). The page is oldest first by updatedAt, then sequence. nextCursor is always set: pass it back for the next page, or keep it and poll; an empty page still moves it on, so the next call reads only new events. Events are the webhook catalog's, with the same data; they are kept 90 days. Load by id to drop the rare repeat. Behind the warehouseExport flag: 404 not_found until it is on for your account.
| Field | Type | Notes |
|---|---|---|
cursor | string | up to 40 characters |
since | string | up to 40 characters |
type | string | up to 60 characters, pattern ^[a-z_]+(\.[a-z_]+)?$ |
limit | integer | 1–500 |
| Field | Type | Notes |
|---|---|---|
events | object[] | required |
events[] | string | required |
events[] | string | required |
events[] | integer | required |
events[] | string | required |
events[] | string | required |
events[] | string | | required |
events[] | map of object | required |
nextCursor | string | required |
hasMore | boolean | required |
GET/v1/organizations/current/warehouse/destinations
The organization's warehouse export destinations: buckets, schedules, state and how far each data set has been written.
API key or OAuth token with organization:read.
Organization admins, or a key, connected app or service account with organization:read. Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
destinations | object[] | required |
destinations[] | string | required |
destinations[] | string | required |
destinations[] | "s3" | | required |
destinations[] | string | required |
destinations[] | string | | required |
destinations[] | string | | required |
destinations[] | "default" | | required |
destinations[] | string | required |
destinations[] | string | required |
destinations[] | "events" | | required |
destinations[] | integer | required |
destinations[] | "active" | | required |
destinations[] | integer | required |
destinations[] | string | | required |
destinations[] | string | | required |
destinations[] | string | | required |
destinations[] | string | | required |
destinations[] | object | required |
destinations[] | string | | required |
destinations[] | string | | required |
destinations[] | string | required |
destinations[] | object | required |
destinations[] | string | required |
destinations[] | string | | required |
GET/v1/organizations/current/warehouse/destinations/{id}
One destination.
API key or OAuth token with organization:read.
As the list. Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
destination | object | required |
destination. | string | required |
destination. | string | required |
destination. | "s3" | | required |
destination. | string | required |
destination. | string | | required |
destination. | string | | required |
destination. | "default" | | required |
destination. | string | required |
destination. | string | required |
destination. | "events" | | required |
destination. | integer | required |
destination. | "active" | | required |
destination. | integer | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | object | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | required |
destination. | object | required |
destination. | string | required |
destination. | string | | required |
GET/v1/organizations/current/warehouse/destinations/{id}/runs
The destination's last 50 runs, newest first: rows and files written, the manifest, and the error of a run that failed.
API key or OAuth token with organization:read.
As the list. Runs are kept 90 days. Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
runs | object[] | required |
runs[] | string | required |
runs[] | string | required |
runs[] | "schedule" | | required |
runs[] | "running" | | required |
runs[] | string | required |
runs[] | string | | required |
runs[] | object | required |
runs[] | integer | required |
runs[] | integer | required |
runs[] | integer | required |
runs[] | integer | required |
runs[] | string | | required |
runs[] | boolean | required |
runs[] | string | | required |
POST/v1/organizations/current/warehouse/destinations
Add a bucket: AWS S3 (with its region), Cloudflare R2 (with the account ID) or Google Cloud Storage (HMAC keys).
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Saving writes a small test file under the prefix first; if the bucket refuses it nothing is saved (422 destination_unreachable, with the test in details.test). The keys need permission to put objects under the prefix and nothing else. The first run is within five minutes. Up to 5 destinations (409 too_many_destinations). Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
name | string | required up to 60 characters |
provider | "s3" | | required |
bucket | string | required pattern ^[a-z0-9][a-z0-9._-]{1,61}[a-z0-9]$ |
region | string | pattern ^[a-z]{2}(-[a-z]+)+-\d{1,2}$ |
accountId | string | pattern ^[a-f0-9]{32}$ |
jurisdiction | "default" | | |
prefix | string | up to 200 characters, pattern ^(?:[A-Za-z0-9!_.*'()=-]+\/){0,8}$, default "50heads/" |
datasets | "events" | | up to 2 items, default ["events"] |
intervalMinutes | 60 | | default 60 |
accessKeyId | string | required up to 128 characters, at least 4 characters, pattern ^[\x21-\x7e]+$ |
secretAccessKey | string | required up to 256 characters, at least 8 characters, pattern ^[\x21-\x7e]+$ |
| Field | Type | Notes |
|---|---|---|
destination | object | required |
destination. | string | required |
destination. | string | required |
destination. | "s3" | | required |
destination. | string | required |
destination. | string | | required |
destination. | string | | required |
destination. | "default" | | required |
destination. | string | required |
destination. | string | required |
destination. | "events" | | required |
destination. | integer | required |
destination. | "active" | | required |
destination. | integer | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | object | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | required |
destination. | object | required |
destination. | string | required |
destination. | string | | required |
test | object | required |
test. | boolean | required |
test. | integer | | required |
test. | "access_denied" | | required |
test. | string | required |
test. | string | required |
PATCH/v1/organizations/current/warehouse/destinations/{id}
Rename, change the prefix, data sets or schedule, pause or resume, or replace the keys.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. New keys or a new prefix are tested with a write first (422 destination_unreachable). Resuming a failing destination runs it within five minutes. Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
name | string | up to 60 characters |
prefix | string | up to 200 characters, pattern ^(?:[A-Za-z0-9!_.*'()=-]+\/){0,8}$ |
datasets | "events" | | up to 2 items |
intervalMinutes | 60 | | |
paused | boolean | |
credentials | object | |
credentials. | string | required up to 128 characters, at least 4 characters, pattern ^[\x21-\x7e]+$ |
credentials. | string | required up to 256 characters, at least 8 characters, pattern ^[\x21-\x7e]+$ |
| Field | Type | Notes |
|---|---|---|
destination | object | required |
destination. | string | required |
destination. | string | required |
destination. | "s3" | | required |
destination. | string | required |
destination. | string | | required |
destination. | string | | required |
destination. | "default" | | required |
destination. | string | required |
destination. | string | required |
destination. | "events" | | required |
destination. | integer | required |
destination. | "active" | | required |
destination. | integer | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | object | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | required |
destination. | object | required |
destination. | string | required |
destination. | string | | required |
DELETE/v1/organizations/current/warehouse/destinations/{id}
Stop exporting to a bucket and delete its keys. Files already written stay in the bucket.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
POST/v1/organizations/current/warehouse/destinations/{id}/test
Test the connection: write a small file with the stored keys.
Portal session only.
Organization admins, signed in. Answers 200 whether or not the write worked; test.ok says which, with the bucket's error code. Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
test | object | required |
test. | boolean | required |
test. | integer | | required |
test. | "access_denied" | | required |
test. | string | required |
test. | string | required |
POST/v1/organizations/current/warehouse/destinations/{id}/run
Run an export now (within five minutes) instead of waiting for the schedule.
Portal session only.
Organization admins, signed in. A paused destination answers 409 destination_paused. Behind the warehouseExport flag (and the organizations flag): 404 not_found until it is on for your organization. Each run writes JSON lines under <prefix><dataset>/dt=<date>/<run>-<n>.jsonl and then a manifest at <prefix>manifests/<time>-<run>.json listing the files, their rows and SHA-256; load the files a manifest lists (a file with no manifest is from a run that failed and is written again). Parquet is not written. Keys are stored encrypted and never returned.
| Field | Type | Notes |
|---|---|---|
destination | object | required |
destination. | string | required |
destination. | string | required |
destination. | "s3" | | required |
destination. | string | required |
destination. | string | | required |
destination. | string | | required |
destination. | "default" | | required |
destination. | string | required |
destination. | string | required |
destination. | "events" | | required |
destination. | integer | required |
destination. | "active" | | required |
destination. | integer | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | | required |
destination. | object | required |
destination. | string | | required |
destination. | string | | required |
destination. | string | required |
destination. | object | required |
destination. | string | required |
destination. | string | | required |
Spend approvals
An organization can ask that some asks wait for a person: over an amount per ask, day or month, at a tier, with images, or always. An ask a policy holds comes back as 202 `approval_required` with its credits held and nothing sent to heads; an approver decides in the 50heads app or at 50heads.com, and the agent reads the outcome here (or waits on the question). Being introduced: 404 `not_found` until it is on for your organization.
GET/v1/approvals
Approvals for the signed-in person: waiting for them (`inbox`), decided (`history`) or the whole workspace's (`workspace`, for owners, admins and billing).
Portal session only.
A person, in the app or at 50heads.com. pendingForYou is the badge on the Answer tab. An empty list while approvals are off.
| Field | Type | Notes |
|---|---|---|
view | "inbox" | | |
state | "pending" | | |
limit | integer | 1–100 |
cursor | string |
| Field | Type | Notes |
|---|---|---|
approvals | object[] | required |
approvals[] | string | required |
approvals[] | "pending" | | required |
approvals[] | string | required |
approvals[] | string | required |
approvals[] | string | required |
approvals[] | string | required |
approvals[] | string | required |
approvals[] | object | required |
approvals[] | string | required |
approvals[] | string | required |
approvals[] | object[] | required |
approvals[] | string | | required |
approvals[] | integer | required |
approvals[] | integer | required |
approvals[] | integer | required |
approvals[] | integer | | required |
approvals[] | "per_ask" | | required |
approvals[] | object | required |
approvals[] | "key" | | required |
approvals[] | string | required |
approvals[] | string | | required |
approvals[] | string | | required |
approvals[] | string | | required |
approvals[] | 1 | | required |
approvals[] | integer | required |
approvals[] | "owner" | | required |
approvals[] | integer | required |
approvals[] | object[] | required |
approvals[] | string | | required |
approvals[] | string | | required |
approvals[] | string | required |
approvals[] | "approve" | | required |
approvals[] | string | | required |
approvals[] | "app" | | required |
approvals[] | string | required |
approvals[] | string | required |
approvals[] | string | required |
approvals[] | string | | required |
approvals[] | boolean | required |
approvals[] | "own_ask" | | required |
approvals[] | integer | required |
approvals[] | boolean | required |
approvals[] | string | required |
pendingForYou | integer | required |
nextCursor | string | | required |
stats | object | | |
stats. | integer | required |
stats. | integer | required |
stats. | integer | required |
stats. | integer | required |
stats. | integer | required |
stats. | integer | required |
stats. | number | | required |
stats. | number | | required |
stats. | integer | | required |
enabled | boolean |
GET/v1/approvals/{id}
What an agent can read about its own approval: the state and, once decided, the approver's role and typed reason.
API key or OAuth token with questions:read.
Poll this (the 202 says how often), or wait on the question. Denied: code: refused_by_policy with the approver's reason and role (owner, admin or billing), never their name. Nobody decided in time: code: approval_expired. Only the account that asked, or a person who can see the approval, can read it; anyone else gets 404.
| Field | Type | Notes |
|---|---|---|
approvalId | string | required |
questionId | string | required |
status | "pending" | | required |
amountPence | integer | required |
approveUrl | string | required |
expiresAt | string | required |
quorum | 1 | | required |
approvedCount | integer | required |
code | "refused_by_policy" | | required |
decision | object | | required |
decision. | "approved" | | required |
decision. | string | | required |
decision. | string | | required |
decision. | string | required |
GET/v1/approvals/{id}/review
The approver's view of one approval: the question, the amount, who asked, who has decided. Opening it is written to the audit trail.
Portal session only.
A person who can see the approval; anyone else gets 404.
| Field | Type | Notes |
|---|---|---|
approval | object | required |
approval. | string | required |
approval. | "pending" | | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | object | required |
approval. | string | required |
approval. | string | required |
approval. | object[] | required |
approval. | string | | required |
approval. | integer | required |
approval. | integer | required |
approval. | integer | required |
approval. | integer | | required |
approval. | "per_ask" | | required |
approval. | object | required |
approval. | "key" | | required |
approval. | string | required |
approval. | string | | required |
approval. | string | | required |
approval. | string | | required |
approval. | 1 | | required |
approval. | integer | required |
approval. | "owner" | | required |
approval. | integer | required |
approval. | object[] | required |
approval. | string | | required |
approval. | string | | required |
approval. | string | required |
approval. | "approve" | | required |
approval. | string | | required |
approval. | "app" | | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | string | | required |
approval. | boolean | required |
approval. | "own_ask" | | required |
approval. | integer | required |
approval. | boolean | required |
approval. | string | required |
POST/v1/approvals/{id}/confirm
The app: Face ID or the passcode succeeded on the phone. Returns a one-use confirmation and opens a five-minute window.
Portal session only.
App sessions only. Every decision over £100.00 needs its own confirmation (confirmationId); smaller ones are covered by a confirm in the last five minutes.
| Field | Type | Notes |
|---|---|---|
method | "biometric" | | required |
| Field | Type | Notes |
|---|---|---|
confirmationId | string | required |
expiresAt | string | required |
windowEndsAt | string | required |
POST/v1/approvals/{id}/decision
Approve or deny. Needs a person: never an API key, a connected app or a service account.
Portal session only.
An approver on a browser session with a fresh proof in x-50h-reauth (spent by the decision), or in the app with a confirmationId. The typed reason goes to the agent and the audit trail. 403 separation_of_duties when the approver's own key made the ask (unless the policy allows it under an amount), 403 not_an_approver, 403 confirm_required (the app has not confirmed it is them, or the confirmation was used or is too old), 409 approval_decided or approval_expired. Approving the last approval a policy needs makes the question live; denying releases the held credits.
| Field | Type | Notes |
|---|---|---|
decision | "approve" | | required |
reason | string | up to 200 characters |
confirmationId | string | up to 100 characters |
| Field | Type | Notes |
|---|---|---|
approval | object | required |
approval. | string | required |
approval. | "pending" | | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | object | required |
approval. | string | required |
approval. | string | required |
approval. | object[] | required |
approval. | string | | required |
approval. | integer | required |
approval. | integer | required |
approval. | integer | required |
approval. | integer | | required |
approval. | "per_ask" | | required |
approval. | object | required |
approval. | "key" | | required |
approval. | string | required |
approval. | string | | required |
approval. | string | | required |
approval. | string | | required |
approval. | 1 | | required |
approval. | integer | required |
approval. | "owner" | | required |
approval. | integer | required |
approval. | object[] | required |
approval. | string | | required |
approval. | string | | required |
approval. | string | required |
approval. | "approve" | | required |
approval. | string | | required |
approval. | "app" | | required |
approval. | string | required |
approval. | string | required |
approval. | string | required |
approval. | string | | required |
approval. | boolean | required |
approval. | "own_ask" | | required |
approval. | integer | required |
approval. | boolean | required |
approval. | string | required |
outcome | "approved" | | required |
GET/v1/approvals/notifications
The person's own push, email, quiet hours and daily digest settings for approvals.
Portal session only.
| Field | Type | Notes |
|---|---|---|
settings | object | required |
settings. | boolean | required |
settings. | boolean | required |
settings. | integer | | required |
settings. | integer | | required |
settings. | boolean | required |
settings. | integer | required 0–23 |
settings. | string | | required |
PUT/v1/approvals/notifications
Change them. Quiet hours are both set or both null.
Portal session only.
| Field | Type | Notes |
|---|---|---|
push | boolean | |
email | boolean | |
quietFrom | integer | | |
quietTo | integer | | |
digest | boolean | |
digestHour | integer | 0–23 |
timezone | string | |
| Field | Type | Notes |
|---|---|---|
settings | object | required |
settings. | boolean | required |
settings. | boolean | required |
settings. | integer | | required |
settings. | integer | | required |
settings. | boolean | required |
settings. | integer | required 0–23 |
settings. | string | | required |
GET/v1/approvals/policies
The organization's approval policies, and the workspaces, projects, keys and people they can name.
Portal session only.
Organization admins only (403 organization_admin_required).
| Field | Type | Notes |
|---|---|---|
policies | object[] | required |
policies[] | string | required |
policies[] | string | required |
policies[] | "organization" | | required |
policies[] | string | | required |
policies[] | string | | required |
policies[] | boolean | required |
policies[] | boolean | required |
policies[] | integer | | required |
policies[] | integer | | required |
policies[] | integer | | required |
policies[] | integer[] | required |
policies[] | boolean | required |
policies[] | object | required |
policies[] | "owner" | | required |
policies[] | object[] | required |
policies[] | 1 | | required |
policies[] | integer | required |
policies[] | "deny" | required |
policies[] | integer | | required |
policies[] | "app" | | required |
policies[] | string | required |
policies[] | string | | required |
targets | object | required |
targets. | object[] | required |
targets. | string | required |
targets. | string | required |
targets. | object[] | required |
targets. | string | required |
targets. | string | required |
targets. | string | | required |
targets. | object[] | required |
targets. | string | required |
targets. | string | required |
targets. | string | | required |
targets. | object[] | required |
targets. | string | required |
targets. | string | | required |
targets. | string | | required |
POST/v1/approvals/policies
Make a policy for the organization, a workspace, a project or a key. One per scope; the narrowest wins.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Approvers must be people in the organization (in the workspace, for a workspace, project or key policy).
| Field | Type | Notes |
|---|---|---|
enabled | boolean | default true |
always | boolean | default false |
perAskPence | integer | | default null |
perDayPence | integer | | default null |
perMonthPence | integer | | default null |
requireForTiers | integer[] | up to 3 items, default [] |
requireForImages | boolean | default false |
approvers | object | default {"roles":["owner","admin"],"people":[]} |
approvers. | "owner" | | up to 3 items, default ["owner","admin"] |
approvers. | string[] | up to 25 items, default [] |
quorum | 1 | | default 1 |
expiresInMinutes | integer | 5–1440, default 60 |
onExpiry | "deny" | default "deny" |
allowSelfApprovalUnderPence | integer | | default null |
notify | "app" | | up to 2 items, default ["app","email"] |
scope | "organization" | | required |
scopeId | string | | default null |
| Field | Type | Notes |
|---|---|---|
policy | object | required |
policy. | string | required |
policy. | string | required |
policy. | "organization" | | required |
policy. | string | | required |
policy. | string | | required |
policy. | boolean | required |
policy. | boolean | required |
policy. | integer | | required |
policy. | integer | | required |
policy. | integer | | required |
policy. | integer[] | required |
policy. | boolean | required |
policy. | object | required |
policy. | "owner" | | required |
policy. | object[] | required |
policy. | 1 | | required |
policy. | integer | required |
policy. | "deny" | required |
policy. | integer | | required |
policy. | "app" | | required |
policy. | string | required |
policy. | string | | required |
PATCH/v1/approvals/policies/{id}
Change a policy. Only what you send changes; asks already waiting keep the approvers and quorum they were held with.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit.
| Field | Type | Notes |
|---|---|---|
enabled | boolean | |
always | boolean | |
perAskPence | integer | | |
perDayPence | integer | | |
perMonthPence | integer | | |
requireForTiers | integer[] | up to 3 items |
requireForImages | boolean | |
approvers | object | |
approvers. | "owner" | | up to 3 items |
approvers. | string[] | up to 25 items |
quorum | 1 | | |
expiresInMinutes | integer | 5–1440 |
allowSelfApprovalUnderPence | integer | | |
notify | "app" | | up to 2 items |
| Field | Type | Notes |
|---|---|---|
policy | object | required |
policy. | string | required |
policy. | string | required |
policy. | "organization" | | required |
policy. | string | | required |
policy. | string | | required |
policy. | boolean | required |
policy. | boolean | required |
policy. | integer | | required |
policy. | integer | | required |
policy. | integer | | required |
policy. | integer[] | required |
policy. | boolean | required |
policy. | object | required |
policy. | "owner" | | required |
policy. | object[] | required |
policy. | 1 | | required |
policy. | integer | required |
policy. | "deny" | required |
policy. | integer | | required |
policy. | "app" | | required |
policy. | string | required |
policy. | string | | required |
DELETE/v1/approvals/policies/{id}
Delete a policy. Asks already waiting are decided as before.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
Organizations
Being introduced for teams that ask for it. An organization holds a team's workspaces, proves the email domains it owns with a DNS record, and sets rules for people on those domains. Signed in at 50heads.com, changes need an organization admin (an owner or admin of one of its workspaces) who has just confirmed it is them. Where the organization has machine identities, API keys and connected apps of an organization admin, and the organization's service accounts, can use the routes marked with a scope (organization:read, organization:write, members:read, members:write, audit:read); the rest stay with a person.
GET/v1/organizations/current
The organization of the team account in use, with your role in it.
API key or OAuth token with organization:read.
The organization of the team named in the account header. A personal account has none: 404 not_in_organization. Any member of its workspaces can read this; role says whether you are an admin.
| Field | Type | Notes |
|---|---|---|
organization | object | required |
organization. | string | required |
organization. | string | required |
organization. | string | required |
organization. | "admin" | | required |
organization. | string | | required |
organization. | object[] | required |
organization. | string | required |
organization. | string | required |
organization. | string | | |
organization. | boolean | |
organization. | map of object | required |
organization. | object | required |
organization. | boolean | required |
organization. | boolean | required |
organization. | boolean | required |
organization. | integer | required 7–90 |
organization. | string[] | required |
organization. | object | | |
organization. | "draft" | | required |
organization. | boolean | required |
organization. | object | |
organization. | boolean | required |
organization. | object | |
organization. | boolean | required |
organization. | integer | | required |
organization. | integer | | required |
organization. | integer | | required |
organization. | boolean | |
organization. | boolean |
PATCH/v1/organizations/current
Rename the organization. Its workspaces keep their names.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account).
| Field | Type | Notes |
|---|---|---|
name | string | required up to 80 characters |
| Field | Type | Notes |
|---|---|---|
organization | object | required |
organization. | string | required |
organization. | string | required |
organization. | string | required |
organization. | "admin" | | required |
organization. | string | | required |
organization. | object[] | required |
organization. | string | required |
organization. | string | required |
organization. | string | | |
organization. | boolean | |
organization. | map of object | required |
organization. | object | required |
organization. | boolean | required |
organization. | boolean | required |
organization. | boolean | required |
organization. | integer | required 7–90 |
organization. | string[] | required |
organization. | object | | |
organization. | "draft" | | required |
organization. | boolean | required |
organization. | object | |
organization. | boolean | required |
organization. | object | |
organization. | boolean | required |
organization. | integer | | required |
organization. | integer | | required |
organization. | integer | | required |
organization. | boolean | |
organization. | boolean |
GET/v1/organizations/current/domains
The organization's domains, each with the TXT record that proves it.
API key or OAuth token with organization:read.
Organization admins only. Removed domains are not listed.
| Field | Type | Notes |
|---|---|---|
domains | object[] | required |
domains[] | string | required |
domains[] | string | required |
domains[] | "pending" | | required |
domains[] | object | required |
domains[] | string | required |
domains[] | "TXT" | required |
domains[] | string | required |
domains[] | string | required |
domains[] | string | | required |
domains[] | string | | required |
domains[] | string | | required |
domains[] | string | | required |
domains[] | string | | required |
POST/v1/organizations/current/domains
Add a domain to prove. It starts as pending, with its TXT record.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). The exact domain only: example.com covers addresses @example.com, not @mail.example.com and never @evil-example.com. Public suffixes (co.uk), free email providers and disposable email domains are refused with domain_not_allowed. Up to 20 domains.
| Field | Type | Notes |
|---|---|---|
domain | string | required up to 253 characters, at least 3 characters |
| Field | Type | Notes |
|---|---|---|
domain | object | required |
domain. | string | required |
domain. | string | required |
domain. | "pending" | | required |
domain. | object | required |
domain. | string | required |
domain. | "TXT" | required |
domain. | string | required |
domain. | string | required |
domain. | string | | required |
domain. | string | | required |
domain. | string | | required |
domain. | string | | required |
domain. | string | | required |
POST/v1/organizations/current/domains/{domainId}/verify
Look the TXT record up now and verify the domain if it is there.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). outcome says what the lookup found: verified, already_verified, record_missing, value_mismatch, lookup_failed (try again later) or held_elsewhere (another organization has verified it). Only one organization can hold a domain. Verified domains are checked again daily; a missing record moves the domain to warning and emails the admins, and after 7 days to failed, when its policies stop applying.
| Field | Type | Notes |
|---|---|---|
outcome | "verified" | | required |
domain | object | required |
domain. | string | required |
domain. | string | required |
domain. | "pending" | | required |
domain. | object | required |
domain. | string | required |
domain. | "TXT" | required |
domain. | string | required |
domain. | string | required |
domain. | string | | required |
domain. | string | | required |
domain. | string | | required |
domain. | string | | required |
domain. | string | | required |
DELETE/v1/organizations/current/domains/{domainId}
Remove a domain. Its policies stop applying at once.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account).
| Field | Type | Notes |
|---|---|---|
ok | true | required |
GET/v1/organizations/current/policies
The rules for people on the organization's verified domains. All off by default.
API key or OAuth token with organization:read.
Organization admins only.
| Field | Type | Notes |
|---|---|---|
policies | object | required |
policies. | boolean | required |
policies. | boolean | required |
policies. | boolean | required |
policies. | integer | required 7–90 |
PATCH/v1/organizations/current/policies
Turn a policy on or off.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). Turning a policy on needs a verified domain (409 domain_not_verified). Policies never delete, merge or move an existing personal account.
| Field | Type | Notes |
|---|---|---|
autoJoin | boolean | |
claimWithNotice | boolean | |
restrictPersonalSignup | boolean | |
noticeDays | integer | 7–90 |
| Field | Type | Notes |
|---|---|---|
policies | object | required |
policies. | boolean | required |
policies. | boolean | required |
policies. | boolean | required |
policies. | integer | required 7–90 |
GET/v1/organizations/current/audit
Who did what in the organization, newest first.
API key or OAuth token with audit:read.
Organization admins only. Read-only: entries cannot be changed or deleted. 50 a page.
| Field | Type | Notes |
|---|---|---|
cursor | string |
| Field | Type | Notes |
|---|---|---|
events | object[] | required |
events[] | string | required |
events[] | string | required |
events[] | object | required |
events[] | string | | required |
events[] | string | | required |
events[] | "organization.created" | | required |
events[] | string | required |
events[] | map of object | required |
nextCursor | string | | required |
GET/v1/organizations/current/audit/events
Every audit event of the organization and its workspaces, newest first, with filters.
API key or OAuth token with audit:read.
Organization admins only (403 organization_admin_required). API keys, connected apps and service accounts with audit:read can read and export where the organization has machine identities (otherwise 403 session_required); retention and legal holds change only with a person. Events come from the organization's log and its workspaces' logs and never hold secrets, codes or anything that identifies a head. Being introduced: 404 not_found until it is on for your organization. Ordered by at, then id; page with nextCursor (no gaps or repeats when events are written between pages).
| Field | Type | Notes |
|---|---|---|
cursor | string | up to 200 characters |
from | string | up to 40 characters |
to | string | up to 40 characters |
actor | string | up to 100 characters |
action | string | up to 60 characters |
workspace | string | up to 64 characters |
limit | integer | 1–200 |
| Field | Type | Notes |
|---|---|---|
events | object[] | required |
events[] | string | required |
events[] | string | required |
events[] | string | required |
events[] | string | | required |
events[] | "organization" | | required |
events[] | object | required |
events[] | "person" | | required |
events[] | string | | required |
events[] | string | | required |
events[] | "organization.created" | | required |
events[] | string | required |
events[] | map of object | required |
events[] | string | | required |
nextCursor | string | | required |
GET/v1/organizations/current/audit/export.jsonl
The audit trail as JSON lines (application/x-ndjson), oldest first, streamed.
API key or OAuth token with audit:read.
Organization admins only (403 organization_admin_required). API keys, connected apps and service accounts with audit:read can read and export where the organization has machine identities (otherwise 403 session_required); retention and legal holds change only with a person. Events come from the organization's log and its workspaces' logs and never hold secrets, codes or anything that identifies a head. Being introduced: 404 not_found until it is on for your organization. One AuditEvent per line, newline-terminated. Events written after the export starts are left for the next one. Up to 1,000,000 events per request: to resume, pass cursor as the last line's <at>|<id>. Each export is itself recorded (audit.exported).
| Field | Type | Notes |
|---|---|---|
cursor | string | up to 200 characters |
from | string | up to 40 characters |
to | string | up to 40 characters |
actor | string | up to 100 characters |
action | string | up to 60 characters |
workspace | string | up to 64 characters |
GET/v1/organizations/current/audit/export.csv
The audit trail as CSV, oldest first, streamed.
API key or OAuth token with audit:read.
Organization admins only (403 organization_admin_required). API keys, connected apps and service accounts with audit:read can read and export where the organization has machine identities (otherwise 403 session_required); retention and legal holds change only with a person. Events come from the organization's log and its workspaces' logs and never hold secrets, codes or anything that identifies a head. Being introduced: 404 not_found until it is on for your organization. Columns: id, at, organization_id, workspace_id, source, actor_type, actor_id, actor_name, action, subject, data (JSON), ip. RFC 4180 with CRLF; a cell starting with =, +, - or @ is prefixed with a single quote so spreadsheets do not run it. Same limits and resuming as the JSONL export.
| Field | Type | Notes |
|---|---|---|
cursor | string | up to 200 characters |
from | string | up to 40 characters |
to | string | up to 40 characters |
actor | string | up to 100 characters |
action | string | up to 60 characters |
workspace | string | up to 64 characters |
GET/v1/organizations/current/audit/retention
How long the organization's audit events are kept.
API key or OAuth token with audit:read.
Organization admins only (403 organization_admin_required). API keys, connected apps and service accounts with audit:read can read and export where the organization has machine identities (otherwise 403 session_required); retention and legal holds change only with a person. Events come from the organization's log and its workspaces' logs and never hold secrets, codes or anything that identifies a head. Being introduced: 404 not_found until it is on for your organization. Six years until an admin sets a period; never less than one year.
| Field | Type | Notes |
|---|---|---|
retention | object | required |
retention. | integer | required |
retention. | boolean | required |
retention. | integer | required |
retention. | integer | required |
retention. | integer | required |
retention. | object | | required |
retention. | string | required |
retention. | string | | required |
retention. | string | | required |
PUT/v1/organizations/current/audit/retention
Set how long audit events are kept (365 to 3,650 days).
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. A daily job deletes events older than the period, except those a legal hold covers. Once set, the period applies to the workspace logs too. 50heads keeps its own records (payments, payouts, fraud checks) for as long as it must, whatever is set here.
| Field | Type | Notes |
|---|---|---|
days | integer | required 365–3650 |
| Field | Type | Notes |
|---|---|---|
retention | object | required |
retention. | integer | required |
retention. | boolean | required |
retention. | integer | required |
retention. | integer | required |
retention. | integer | required |
retention. | object | | required |
retention. | string | required |
retention. | string | | required |
retention. | string | | required |
GET/v1/organizations/current/audit/holds
Legal holds: open ones first, then released ones.
API key or OAuth token with audit:read.
Organization admins only (403 organization_admin_required). API keys, connected apps and service accounts with audit:read can read and export where the organization has machine identities (otherwise 403 session_required); retention and legal holds change only with a person. Events come from the organization's log and its workspaces' logs and never hold secrets, codes or anything that identifies a head. Being introduced: 404 not_found until it is on for your organization.
| Field | Type | Notes |
|---|---|---|
holds | object[] | required |
holds[] | string | required |
holds[] | object | required |
holds[] | boolean | required |
holds[] | string[] | required |
holds[] | string[] | required |
holds[] | string | required |
holds[] | boolean | required |
holds[] | object | required |
holds[] | string | required |
holds[] | string | | required |
holds[] | string | required |
holds[] | object | | required |
holds[] | string | required |
holds[] | string | | required |
holds[] | string | | required |
POST/v1/organizations/current/audit/holds
Stop audit events being deleted: everything, or named workspaces or people.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Up to 50 open holds (409 too_many_holds). A workspace must be one of the organization's (404 workspace_not_found).
| Field | Type | Notes |
|---|---|---|
reason | string | required up to 500 characters |
scope | object | required |
scope. | boolean | default false |
scope. | string[] | up to 50 items, default [] |
scope. | string[] | up to 50 items, default [] |
| Field | Type | Notes |
|---|---|---|
hold | object | required |
hold. | string | required |
hold. | object | required |
hold. | boolean | required |
hold. | string[] | required |
hold. | string[] | required |
hold. | string | required |
hold. | boolean | required |
hold. | object | required |
hold. | string | required |
hold. | string | | required |
hold. | string | required |
hold. | object | | required |
hold. | string | required |
hold. | string | | required |
hold. | string | | required |
POST/v1/organizations/current/audit/holds/{holdId}/release
Release a legal hold. Deletion under the retention period resumes at the next daily run.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. 409 hold_released if it was already released.
| Field | Type | Notes |
|---|---|---|
hold | object | required |
hold. | string | required |
hold. | object | required |
hold. | boolean | required |
hold. | string[] | required |
hold. | string[] | required |
hold. | string | required |
hold. | boolean | required |
hold. | object | required |
hold. | string | required |
hold. | string | | required |
hold. | string | required |
hold. | object | | required |
hold. | string | required |
hold. | string | | required |
hold. | string | | required |
GET/v1/organizations/joinable
Organizations you may join because your verified email is on one of their domains.
Portal session only.
Only organizations with auto-join on, and only for an email address a sign-in has proved.
| Field | Type | Notes |
|---|---|---|
organizations | object[] | required |
organizations[] | string | required |
organizations[] | string | required |
organizations[] | string | required |
organizations[] | string | required |
organizations[] | string | required |
organizations[] | "viewer" | required |
POST/v1/organizations/join
Join an organization's default workspace as a viewer.
Portal session only.
Your personal account and its credits stay as they are. 403 not_joinable when the organization does not list you.
| Field | Type | Notes |
|---|---|---|
organizationId | string | required up to 64 characters |
| Field | Type | Notes |
|---|---|---|
organizationId | string | required |
workspaceId | string | required |
role | "viewer" | required |
GET/v1/organizations/current/security-policies
Sign-in rules for everyone in the organization's workspaces. All off by default.
API key or OAuth token with organization:read.
Organization admins only.
| Field | Type | Notes |
|---|---|---|
policies | object | required |
policies. | boolean | required |
policies. | integer | | required |
policies. | integer | | required |
policies. | integer | | required |
PATCH/v1/organizations/current/security-policies
Require two-step sign-in, limit session age and idle time, shorten the re-authentication window.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). Policies apply to new and existing sessions: a session older than a new maximum ends on its next request (401 session_ended), and an OAuth refresh older than it answers invalid_grant. With two-step required, sensitive actions answer 403 two_step_required until the person adds two-step sign-in or a passkey; adding one is never blocked. Sends a policy.changed event.
| Field | Type | Notes |
|---|---|---|
requireTwoStep | boolean | |
maxSessionAgeMinutes | integer | | |
idleTimeoutMinutes | integer | | |
reauthWindowMinutes | integer | |
| Field | Type | Notes |
|---|---|---|
policies | object | required |
policies. | boolean | required |
policies. | integer | | required |
policies. | integer | | required |
policies. | integer | | required |
GET/v1/organizations/requirements
What your organizations ask of you: two-step sign-in, session limits.
Portal session only.
Read after sign-in. With twoStep.required and not enrolled, set up two-step sign-in or a passkey first.
| Field | Type | Notes |
|---|---|---|
requirements | object | required |
requirements. | object | required |
requirements. | boolean | required |
requirements. | boolean | required |
requirements. | string[] | required |
requirements. | integer | | required |
requirements. | integer | | required |
requirements. | integer | | required |
GET/v1/organizations/current/people
Everyone in the organization, across every team.
Portal session only.
Organization admins only (403 organization_admin_required). Active members of any of its teams, and people its identity provider provisioned (still listed when SCIM turned them off). Each with their teams and roles, SCIM or not, single sign-on linked or not, last sign-in and live sessions; no IP addresses. Ordered by email; q matches part of a name or address; page with nextCursor.
| Field | Type | Notes |
|---|---|---|
q | string | up to 100 characters |
cursor | string | up to 400 characters |
limit | integer | 1–200 |
| Field | Type | Notes |
|---|---|---|
people | object[] | required |
people[] | string | required |
people[] | string | | required |
people[] | string | required |
people[] | object[] | required |
people[] | string | required |
people[] | string | required |
people[] | "owner" | | required |
people[] | boolean | required |
people[] | object | | required |
people[] | boolean | required |
people[] | boolean | required |
people[] | string | | required |
people[] | integer | required |
nextCursor | string | | required |
GET/v1/organizations/current/members/{userId}/sessions
A member's live sessions, on the web and in the app.
API key or OAuth token with members:read.
Organization admins only. No IP addresses. 404 for someone not in the organization.
| Field | Type | Notes |
|---|---|---|
userId | string | required |
sessions | object[] | required |
sessions[] | string | required |
sessions[] | "web" | | required |
sessions[] | string | required |
sessions[] | string | | required |
sessions[] | "email" | | required |
sessions[] | string | required |
sessions[] | string | | required |
DELETE/v1/organizations/current/members/{userId}/sessions
Sign a member out everywhere.
API key or OAuth token with members:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). Every session ends on its next request.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
revoked | integer | required |
POST/v1/organizations/current/workspaces/{workspaceId}/owner
Hand a workspace to another of its members.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Only the workspace's owner or the owner of the organization's main workspace (403 owner_required). The new owner must be an active member (400 not_a_member) who owns no other open workspace in this organization (409 owns_workspace_in_organization; a person may own one workspace in each organization). The previous owner becomes an admin. An owner cannot be deprovisioned until this is done.
| Field | Type | Notes |
|---|---|---|
userId | string | required up to 64 characters |
| Field | Type | Notes |
|---|---|---|
workspaceId | string | required |
ownerId | string | required |
previousOwnerId | string | required |
GET/v1/organizations
The organizations you are in, with the workspaces you are in and your role.
API key or OAuth token with organization:read.
Signed in: every organization the flag serves where you are an active member of a workspace; role is admin when you own or administer one of its open workspaces. With an API key, a connected app or a service account: only the organization of the workspace it works in.
| Field | Type | Notes |
|---|---|---|
organizations | object[] | required |
organizations[] | string | required |
organizations[] | string | required |
organizations[] | "admin" | | required |
organizations[] | string | | required |
organizations[] | object[] | required |
organizations[] | string | required |
organizations[] | string | required |
organizations[] | "owner" | | required |
organizations[] | boolean | required |
GET/v1/organizations/current/workspaces
Every workspace of the organization: owner, members, pending invitations, cost center.
API key or OAuth token with organization:read.
Organization admins only. Closed workspaces are listed last, with closedAt; they are read-only.
| Field | Type | Notes |
|---|---|---|
workspaces | object[] | required |
workspaces[] | string | required |
workspaces[] | string | required |
workspaces[] | string | required |
workspaces[] | string | | required |
workspaces[] | string | | required |
workspaces[] | integer | required |
workspaces[] | integer | required |
workspaces[] | string | | required |
workspaces[] | boolean | required |
workspaces[] | string | required |
workspaces[] | string | | required |
POST/v1/organizations/current/workspaces
Make a workspace in the organization.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. The owner is you, or ownerId: someone already in one of its open workspaces (400 not_a_member). A person may own one open workspace in each organization (409 owns_workspace_in_organization). Sends workspace.created.
| Field | Type | Notes |
|---|---|---|
name | string | required up to 80 characters |
ownerId | string | up to 64 characters |
costCenter | string | |
| Field | Type | Notes |
|---|---|---|
workspace | object | required |
workspace. | string | required |
workspace. | string | required |
workspace. | string | required |
workspace. | string | | required |
workspace. | string | | required |
workspace. | integer | required |
workspace. | integer | required |
workspace. | string | | required |
workspace. | boolean | required |
workspace. | string | required |
workspace. | string | | required |
PATCH/v1/organizations/current/workspaces/{workspaceId}
Rename a workspace, or set its cost center label.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. costCenter null removes the label. The label is printed on the workspace's invoices from then on and carried on spend reports and exports. A closed workspace cannot change (409 workspace_closed).
| Field | Type | Notes |
|---|---|---|
name | string | up to 80 characters |
costCenter | string | |
| Field | Type | Notes |
|---|---|---|
workspace | object | required |
workspace. | string | required |
workspace. | string | required |
workspace. | string | required |
workspace. | string | | required |
workspace. | string | | required |
workspace. | integer | required |
workspace. | integer | required |
workspace. | string | | required |
workspace. | boolean | required |
workspace. | string | required |
workspace. | string | | required |
PUT/v1/organizations/current/default-workspace
Choose the organization's main workspace.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. The workspace auto-join, SCIM and single sign-on put people in by default. Only the owner of the current main workspace can choose (403 owner_required), or any admin once it is closed. A closed workspace cannot be chosen (409 workspace_closed).
| Field | Type | Notes |
|---|---|---|
workspaceId | string | required up to 64 characters |
| Field | Type | Notes |
|---|---|---|
defaultWorkspaceId | string | required |
GET/v1/organizations/current/moves
Requests to move teams into the organization.
API key or OAuth token with organization:read.
Organization admins only. Newest first. A pending request past expiresAt reads as expired.
| Field | Type | Notes |
|---|---|---|
moves | object[] | required |
moves[] | string | required |
moves[] | string | required |
moves[] | string | required |
moves[] | string | required |
moves[] | string | required |
moves[] | string | required |
moves[] | object | required |
moves[] | string | required |
moves[] | string | | required |
moves[] | "pending" | | required |
moves[] | string | required |
moves[] | string | required |
moves[] | string | | required |
POST/v1/organizations/current/moves
Ask a team's owner to move the team into the organization.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. The team's owner reads its id on their Team page. Refused when the team's organization has other open workspaces (409 source_has_other_workspaces), holds a verified domain, single sign-on or SCIM (409 source_has_identity), when its owner already owns a workspace here (409 owns_workspace_in_organization), when asks wait for a spend approval (409 pending_approvals), or a request is already open (409 move_exists). The owner is emailed and has 14 days to accept, with a fresh re-authentication, on their Team page. When they do, the team keeps its members, credits, questions and history, and its old organization is closed with its audit kept.
| Field | Type | Notes |
|---|---|---|
workspaceId | string | required up to 64 characters |
| Field | Type | Notes |
|---|---|---|
move | object | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | object | required |
move. | string | required |
move. | string | | required |
move. | "pending" | | required |
move. | string | required |
move. | string | required |
move. | string | | required |
DELETE/v1/organizations/current/moves/{id}
Withdraw a request to move a team in.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Only a pending request (409 move_not_allowed).
| Field | Type | Notes |
|---|---|---|
move | object | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | string | required |
move. | object | required |
move. | string | required |
move. | string | | required |
move. | "pending" | | required |
move. | string | required |
move. | string | required |
move. | string | | required |
GET/v1/organizations/current/invitations
Invitations not yet accepted, in every workspace of the organization.
API key or OAuth token with members:read.
Organization admins only. Newest first; expired invitations stay listed until they are resent or revoked.
| Field | Type | Notes |
|---|---|---|
invitations | object[] | required |
invitations[] | string | required |
invitations[] | string | required |
invitations[] | "owner" | | required |
invitations[] | string | required |
invitations[] | string | required |
invitations[] | object | | required |
invitations[] | string | required |
invitations[] | string | | required |
invitations[] | string | required |
invitations[] | string | | required |
invitations[] | boolean | required |
POST/v1/organizations/current/invitations/{id}/resend
Send an invitation again, with a new link and seven more days.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. The old link stops working. At most 30 invitations an hour per person.
| Field | Type | Notes |
|---|---|---|
invitation | object | required |
invitation. | string | required |
invitation. | string | required |
invitation. | "owner" | | required |
invitation. | string | required |
invitation. | string | required |
invitation. | object | | required |
invitation. | string | required |
invitation. | string | | required |
invitation. | string | required |
invitation. | string | | required |
invitation. | boolean | required |
DELETE/v1/organizations/current/invitations/{id}
Revoke an invitation.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
DELETE/v1/organizations/current/people/{userId}
Take someone out of every workspace of the organization.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. The keys and app grants they made for those workspaces stop; their questions stay with the workspaces. Refused while they own a workspace here (409 owns_workspace_in_organization: hand it over first) and for people your identity provider manages (409 scim_managed: remove them there). Their own account is untouched.
| Field | Type | Notes |
|---|---|---|
userId | string | required |
workspacesLeft | string[] | required |
PUT/v1/organizations/current/people/{userId}/role
Change someone's role in one workspace of the organization.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Not the owner's role (409 owner_role); not in a closed workspace (409 workspace_closed). An admin's choice replaces the identity provider's group mapping for that person from then on.
| Field | Type | Notes |
|---|---|---|
workspaceId | string | required up to 64 characters |
role | "admin" | | required |
| Field | Type | Notes |
|---|---|---|
userId | string | required |
workspaceId | string | required |
role | string | required |
GET/v1/organizations/current/spend
Spend by cost center for a month.
API key or OAuth token with organization:read.
Organization admins only. Credits the workspaces' questions took in the month (UTC), less what came back, by workspace and cost center: a project's label wins over its workspace's; questions with neither have costCenter null.
| Field | Type | Notes |
|---|---|---|
month | string | pattern ^\d{4}-(0[1-9]|1[0-2])$ |
| Field | Type | Notes |
|---|---|---|
month | string | required |
totalSpentPence | integer | required |
totalQuestions | integer | required |
rows | object[] | required |
rows[] | string | | required |
rows[] | string | required |
rows[] | string | required |
rows[] | integer | required |
rows[] | integer | required |
GET/v1/organizations/current/spend.csv
Spend by cost center as CSV.
API key or OAuth token with organization:read.
Organization admins only. Columns: month, cost_center, workspace_id, workspace_name, questions, spent_credits. RFC 4180 with CRLF; formula cells are quoted.
| Field | Type | Notes |
|---|---|---|
month | string | pattern ^\d{4}-(0[1-9]|1[0-2])$ |
GET/v1/organizations/current/scim
SCIM provisioning: the base URL, the default role and counts.
API key or OAuth token with organization:read.
Organization admins only. Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
settings | object | required |
settings. | string | required |
settings. | "admin" | | required |
settings. | string | | required |
settings. | integer | required |
settings. | integer | required |
settings. | integer | required |
PATCH/v1/organizations/current/scim
Set the role a provisioned person gets when none of their groups is mapped.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
defaultRole | "admin" | | required |
| Field | Type | Notes |
|---|---|---|
defaultRole | "admin" | | required |
GET/v1/organizations/current/scim/tokens
The SCIM tokens that work now (never the tokens themselves).
API key or OAuth token with organization:read.
Organization admins only. Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
tokens | object[] | required |
tokens[] | string | required |
tokens[] | string | required |
tokens[] | string | required |
tokens[] | string | required |
tokens[] | string | | required |
tokens[] | string | | required |
tokens[] | string | | required |
POST/v1/organizations/current/scim/tokens
Make a SCIM token for the identity provider. It is shown once.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Stored as a SHA-256 hash. Up to 5 live tokens (409 too_many_tokens). Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
label | string | up to 60 characters, default "Identity provider" |
| Field | Type | Notes |
|---|---|---|
token | object | required |
token. | string | required |
token. | string | required |
token. | string | required |
token. | string | required |
token. | string | | required |
token. | string | | required |
token. | string | | required |
secret | string | required |
baseUrl | string | required |
POST/v1/organizations/current/scim/tokens/{tokenId}/rotate
Replace a SCIM token; the old one keeps working for the overlap.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. overlapHours 0 ends the old token at once; up to 168. 409 already_rotated. Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
overlapHours | integer | 0–168, default 24 |
| Field | Type | Notes |
|---|---|---|
token | object | required |
token. | string | required |
token. | string | required |
token. | string | required |
token. | string | required |
token. | string | | required |
token. | string | | required |
token. | string | | required |
secret | string | required |
baseUrl | string | required |
DELETE/v1/organizations/current/scim/tokens/{tokenId}
End a SCIM token at once.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
GET/v1/organizations/current/scim/groups
The groups the identity provider has pushed.
API key or OAuth token with organization:read.
Organization admins only. Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
groups | object[] | required |
groups[] | string | required |
groups[] | string | required |
groups[] | string | | required |
groups[] | integer | required |
groups[] | string | required |
groups[] | string | required |
GET/v1/organizations/current/scim/mappings
Which group gives which role in which workspace.
API key or OAuth token with organization:read.
Organization admins only. A person in several mapped groups gets the highest role in each workspace (admin, member, billing, viewer); a person in no mapped group gets the default role in the default workspace. Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
mappings | object[] | required |
mappings[] | string | required |
mappings[] | string | required |
mappings[] | string | required |
mappings[] | string | required |
mappings[] | string | required |
mappings[] | "admin" | | required |
mappings[] | string | required |
mappings[] | string | required |
POST/v1/organizations/current/scim/mappings
Give a group's members a role in a workspace.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). The group's members get the role at once. 409 mapping_exists. Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
groupId | string | required up to 64 characters |
workspaceId | string | required up to 64 characters |
role | "admin" | | required |
| Field | Type | Notes |
|---|---|---|
mapping | object | required |
mapping. | string | required |
mapping. | string | required |
mapping. | string | required |
mapping. | string | required |
mapping. | string | required |
mapping. | "admin" | | required |
mapping. | string | required |
mapping. | string | required |
PATCH/v1/organizations/current/scim/mappings/{mappingId}
Change the role a group gives.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
role | "admin" | | required |
| Field | Type | Notes |
|---|---|---|
mapping | object | required |
mapping. | string | required |
mapping. | string | required |
mapping. | string | required |
mapping. | string | required |
mapping. | string | required |
mapping. | "admin" | | required |
mapping. | string | required |
mapping. | string | required |
DELETE/v1/organizations/current/scim/mappings/{mappingId}
Stop a group giving a role. Its members lose the role at once.
API key or OAuth token with organization:write.
Organization admins only (403 organization_admin_required). Signed in, with a fresh proof in the x-50h-reauth header (401 reauth_required); with an API key, a connected app or a service account, with the scope named here and no proof, where the organization has machine identities (otherwise 403 session_required). The key's or app's person must be an organization admin. Every change is written to the organization's audit, with who made it (a person, a key, an app or a service account). Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
GET/v1/organizations/current/scim/log
The last SCIM requests and what came of each.
API key or OAuth token with organization:read.
Organization admins only. No request bodies and no tokens. Kept 90 days. Behind the scim sub-flag: 404 not_found while it is off. The SCIM protocol itself is at /scim/v2 for the identity provider (Okta, Microsoft Entra ID), with the token as its bearer; see the SCIM setup guide.
| Field | Type | Notes |
|---|---|---|
limit | integer | 1–500 |
| Field | Type | Notes |
|---|---|---|
entries | object[] | required |
entries[] | string | required |
entries[] | string | required |
entries[] | string | required |
entries[] | string | required |
entries[] | integer | required |
entries[] | string | required |
entries[] | string | | required |
entries[] | string | | required |
entries[] | string | | required |
GET/v1/organizations/current/sso
The organization's single sign-on connection, the OIDC redirect URI, and the SAML values (entity ID, ACS URL, metadata URL) to give your identity provider.
API key or OAuth token with organization:read.
Organization admins only. connection is null until one is saved. The client secret is never returned. connection.protocol is oidc or saml; for SAML, connection.saml has the identity provider's entity ID, single sign-on URL, metadata URL and certificates (fingerprints and expiry, never the certificate itself). saml is this organization's service provider values whatever the protocol in use.
| Field | Type | Notes |
|---|---|---|
connection | object | | required |
connection. | string | required |
connection. | "oidc" | | required |
connection. | string | required |
connection. | string | required |
connection. | boolean | required |
connection. | string | | required |
connection. | "client_secret_basic" | | required |
connection. | string | | required |
connection. | "admin" | | required |
connection. | "draft" | | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | object | | required |
connection. | string | required |
connection. | object | required |
connection. | string | required |
connection. | boolean | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | string | | required |
connection. | object | | required |
connection. | string | required |
connection. | string | required |
connection. | string | | required |
connection. | object[] | required |
connection. | boolean | required |
redirectUri | string | required |
scopes | string[] | required |
saml | object | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
PUT/v1/organizations/current/sso
Save the connection: OpenID Connect (issuer, client id and secret, token method) or SAML 2.0 (the identity provider's metadata), and where new people join.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. 201 the first time. OIDC (protocol left out or oidc): the issuer's discovery document is read before saving (400 sso_discovery_failed); the secret is required the first time and kept when left out. SAML (protocol: "saml"): metadataUrl (read now, https on a public host, 6-second timeout, no redirects) or metadataXml, one of them; metadata that cannot be read, wants signed requests or has no HTTP-Redirect single sign-on URL is 400 saml_metadata_invalid; allowIdpInitiated (default false) accepts sign-ins started at the identity provider. A provider change (OIDC issuer, client id, secret or token method; SAML entity ID, single sign-on URL or certificates replaced; or a switch of protocol) needs a new test before people can sign in, and is refused while enforcement is on (409 sso_enforced). defaultRole is admin, member or viewer, never owner.
| Field | Type | Notes |
|---|---|---|
connection | object | | required |
connection. | string | required |
connection. | "oidc" | | required |
connection. | string | required |
connection. | string | required |
connection. | boolean | required |
connection. | string | | required |
connection. | "client_secret_basic" | | required |
connection. | string | | required |
connection. | "admin" | | required |
connection. | "draft" | | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | object | | required |
connection. | string | required |
connection. | object | required |
connection. | string | required |
connection. | boolean | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | string | | required |
connection. | object | | required |
connection. | string | required |
connection. | string | required |
connection. | string | | required |
connection. | object[] | required |
connection. | boolean | required |
redirectUri | string | required |
scopes | string[] | required |
saml | object | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
PATCH/v1/organizations/current/sso
Change part of the connection, or turn single sign-on on or off with `enabled`.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Turning it on needs a successful test sign-in since the last provider change (409 sso_test_required) and a verified domain. Turning it off is refused while enforcement is on. OIDC fields on a SAML connection, or SAML fields on an OIDC one, are 400 protocol_mismatch. SAML certificate rotation: new metadata with keepPreviousCertificate: true keeps the certificate in use beside the new one (at most two, 409 too_many_certificates), and removeCertificate (a fingerprint) drops one later (409 last_certificate for the only one); neither needs a new test or turning enforcement off.
| Field | Type | Notes |
|---|---|---|
issuer | string | up to 300 characters, at least 8 characters |
clientId | string | up to 300 characters |
clientSecret | string | up to 1000 characters |
tokenAuthMethod | "client_secret_basic" | | |
defaultWorkspaceId | string | | |
defaultRole | "admin" | | |
enabled | boolean | |
metadataUrl | string | up to 1000 characters, at least 8 characters |
metadataXml | string | up to 200000 characters, at least 20 characters |
keepPreviousCertificate | boolean | |
removeCertificate | string | pattern ^[0-9a-f]{64}$ |
allowIdpInitiated | boolean |
| Field | Type | Notes |
|---|---|---|
connection | object | | required |
connection. | string | required |
connection. | "oidc" | | required |
connection. | string | required |
connection. | string | required |
connection. | boolean | required |
connection. | string | | required |
connection. | "client_secret_basic" | | required |
connection. | string | | required |
connection. | "admin" | | required |
connection. | "draft" | | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | object | | required |
connection. | string | required |
connection. | object | required |
connection. | string | required |
connection. | boolean | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | string | | required |
connection. | object | | required |
connection. | string | required |
connection. | string | required |
connection. | string | | required |
connection. | object[] | required |
connection. | boolean | required |
redirectUri | string | required |
scopes | string[] | required |
saml | object | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
POST/v1/organizations/current/sso/test
Start your own test sign-in: open `url`, sign in at your identity provider, and come back to organization settings.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. The result lands on the connection (lastTest) and in the error log; the page you come back to has sso_test=ok or an error code.
| Field | Type | Notes |
|---|---|---|
url | string | required |
expiresAt | string | required |
GET/v1/organizations/current/sso/events
The single sign-on log: tests, failed sign-ins and account links, newest first.
API key or OAuth token with organization:read.
Organization admins only. Codes and plain messages only: no token is ever kept.
| Field | Type | Notes |
|---|---|---|
cursor | string |
| Field | Type | Notes |
|---|---|---|
events | object[] | required |
events[] | string | required |
events[] | string | required |
events[] | "sign_in" | | required |
events[] | "ok" | | required |
events[] | string | | required |
events[] | string | | required |
events[] | string | | required |
nextCursor | string | | required |
PATCH/v1/organizations/current/sso/enforce
Require single sign-on for addresses on the verified domains, or stop requiring it.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. On: email codes stop for those addresses and passkey sign-in is kept only for break-glass owners. It can only be turned on by an admin whose own test sign-in since the last change worked (409 sso_test_required), so nobody locks themselves out. Off is always allowed.
| Field | Type | Notes |
|---|---|---|
enforce | boolean | required |
| Field | Type | Notes |
|---|---|---|
connection | object | | required |
connection. | string | required |
connection. | "oidc" | | required |
connection. | string | required |
connection. | string | required |
connection. | boolean | required |
connection. | string | | required |
connection. | "client_secret_basic" | | required |
connection. | string | | required |
connection. | "admin" | | required |
connection. | "draft" | | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | object | | required |
connection. | string | required |
connection. | object | required |
connection. | string | required |
connection. | boolean | required |
connection. | boolean | required |
connection. | string | | required |
connection. | string | required |
connection. | string | | required |
connection. | object | | required |
connection. | string | required |
connection. | string | required |
connection. | string | | required |
connection. | object[] | required |
connection. | boolean | required |
redirectUri | string | required |
scopes | string[] | required |
saml | object | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
saml. | string | required |
GET/v1/organizations/current/sso/break-glass
Owners who keep passkey sign-in while single sign-on is required.
API key or OAuth token with organization:read.
Organization admins only. Every use is written to the audit and emailed to every admin.
| Field | Type | Notes |
|---|---|---|
members | object[] | required |
members[] | string | required |
members[] | string | required |
members[] | string | | required |
members[] | string | required |
members[] | boolean | required |
max | integer | required |
POST/v1/organizations/current/sso/break-glass
Give an owner break-glass access (up to two).
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Owners only (403 organization_owner_required). The person must be an owner of one of the organization's workspaces with a passkey on their account.
| Field | Type | Notes |
|---|---|---|
userId | string | required up to 64 characters |
| Field | Type | Notes |
|---|---|---|
members | object[] | required |
members[] | string | required |
members[] | string | required |
members[] | string | | required |
members[] | string | required |
members[] | boolean | required |
max | integer | required |
DELETE/v1/organizations/current/sso/break-glass/{userId}
Remove an owner's break-glass access.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Owners only.
| Field | Type | Notes |
|---|---|---|
members | object[] | required |
members[] | string | required |
members[] | string | required |
members[] | string | | required |
members[] | string | required |
members[] | boolean | required |
max | integer | required |
GET/v1/organizations/current/service-accounts
The organization's service accounts: machine identities it owns, each with its scopes, caps, workspace and client secrets (never the secrets themselves).
API key or OAuth token with organization:read.
Organization admins, or a key, connected app or service account with organization:read. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
serviceAccounts | object[] | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | required |
serviceAccounts[] | "active" | | required |
serviceAccounts[] | "questions:read" | | required |
serviceAccounts[] | integer | required |
serviceAccounts[] | integer | | required |
serviceAccounts[] | integer | required |
serviceAccounts[] | string | required |
serviceAccounts[] | "client_secret" | | required |
serviceAccounts[] | object[] | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | | required |
serviceAccounts[] | string | | required |
serviceAccounts[] | object | | required |
serviceAccounts[] | map of object[] | required up to 5 items |
serviceAccounts[] | string | required |
serviceAccounts[] | object | | required |
serviceAccounts[] | string | required |
serviceAccounts[] | string | | required |
serviceAccounts[] | string | | required |
serviceAccounts[] | string | | required |
GET/v1/organizations/current/service-accounts/{id}
One service account.
API key or OAuth token with organization:read.
As the list. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
POST/v1/organizations/current/service-accounts
Make a service account. Its client secret is in this response only.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. It acts in the workspace you choose (the organization's main workspace by default) with the admin role there, limited by its scopes, and spends up to its daily and per-question caps. Up to 50 (409 too_many_service_accounts). With authMethod: private_key_jwt, send your public keys in jwks and no secret is made. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
name | string | required up to 60 characters |
scopes | "questions:read" | | required |
capDailyPence | integer | required 100–10000000 |
capPerQuestionPence | integer | | |
workspaceId | string | up to 64 characters |
authMethod | "client_secret" | | default "client_secret" |
jwks | object | |
jwks. | map of object[] | required up to 5 items |
jwks. | "EC" | | required |
jwks. | string | up to 200 characters |
jwks. | "ES256" | | |
jwks. | "sig" | |
jwks. | string | up to 20 characters |
jwks. | string | up to 2000 characters |
jwks. | string | up to 2000 characters |
jwks. | string | up to 2000 characters |
jwks. | string | up to 20 characters |
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
clientSecret | string | | required |
tokenEndpoint | string | required |
PATCH/v1/organizations/current/service-accounts/{id}
Rename a service account, or change its scopes, caps or workspace.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. New scopes and caps apply to its next request. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
name | string | up to 60 characters |
scopes | "questions:read" | | |
capDailyPence | integer | 100–10000000 |
capPerQuestionPence | integer | | |
workspaceId | string | up to 64 characters |
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
POST/v1/organizations/current/service-accounts/{id}/disable
Turn a service account off: its tokens fail on their next request and it gets no new ones.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
POST/v1/organizations/current/service-accounts/{id}/enable
Turn a service account back on.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
DELETE/v1/organizations/current/service-accounts/{id}
Delete a service account. Its tokens, secrets and the webhook endpoints it made stop; the questions it asked stay with the workspace.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
ok | true | required |
POST/v1/organizations/current/service-accounts/{id}/secrets
A new client secret, shown once. The old one keeps working for `overlapHours` (24 by default, 0 ends it now, up to 168).
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. At most two secrets work at once. A service account on private_key_jwt moves to its client secret. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
overlapHours | integer | 0–168, default 24 |
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
clientSecret | string | | required |
tokenEndpoint | string | required |
DELETE/v1/organizations/current/service-accounts/{id}/secrets/{secretId}
End one client secret now.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
PUT/v1/organizations/current/service-accounts/{id}/jwks
Use private_key_jwt with these public keys (ES256 or RS256, up to 5). Every client secret stops working.
Portal session only.
Organization admins only (403 organization_admin_required), on a browser session with a fresh proof in the x-50h-reauth header (401 reauth_required). It needs a person: API keys, connected apps and service accounts get 403 session_required. Every change is written to the organization's audit. The assertion's iss and sub are the client id, its aud the token endpoint or the issuer, at most five minutes old, each jti once. Behind the machineIdentities sub-flag: 404 not_found while it is off. A service account gets tokens from https://auth.50heads.com/token with grant_type=client_credentials and its client id and secret (HTTP Basic or the body) or a private_key_jwt assertion; no refresh token, ask again when it expires.
| Field | Type | Notes |
|---|---|---|
jwks | object | required |
jwks. | map of object[] | required up to 5 items |
jwks. | "EC" | | required |
jwks. | string | up to 200 characters |
jwks. | "ES256" | | |
jwks. | "sig" | |
jwks. | string | up to 20 characters |
jwks. | string | up to 2000 characters |
jwks. | string | up to 2000 characters |
jwks. | string | up to 2000 characters |
jwks. | string | up to 20 characters |
| Field | Type | Notes |
|---|---|---|
serviceAccount | object | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | "active" | | required |
serviceAccount. | "questions:read" | | required |
serviceAccount. | integer | required |
serviceAccount. | integer | | required |
serviceAccount. | integer | required |
serviceAccount. | string | required |
serviceAccount. | "client_secret" | | required |
serviceAccount. | object[] | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | object | | required |
serviceAccount. | map of object[] | required up to 5 items |
serviceAccount. | string | required |
serviceAccount. | object | | required |
serviceAccount. | string | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
serviceAccount. | string | | required |
JSON lines exports
GET /v2/questions/{id}/export.jsonl and GET /v2/sets/{id}/export.jsonl return every answer as JSON lines (application/x-ndjson): one JSON object per answer, each on its own line, for scripts and model training. They carry the same fields as the CSV export, plus choice and cohortHash, and nothing that identifies a head. The question export takes the same filters as the CSV; an empty body means no answers match.
curl -s https://api.50heads.com/v2/questions/q_8f2k1x/export.jsonl \
-H "Authorization: Bearer $FIFTYHEADS_API_KEY" > answers.jsonlOne line:
{"questionId":"q_8f2k1x","type":"ranking","question":"Rank these names for a bakery","options":["Crumb","Loafers","Proof"],"cohortHash":"ch1_3f9a0c2e71b4d856","answeredAt":"2026-10-10T09:41:12.000Z","answer":"Crumb > Proof > Loafers","choice":{"order":[0,2,1]},"text":null,"translatedText":null,"reason":"Short and warm","translatedReason":null,"tier":1,"attestationRef":"att_5d0e7a91c2b4f3e86a17"}The choice field
choice is the answer as indexes into options, counted from 0, so you never parse a label. It is null for free text and for a click test, whose taps are in taps. The same field is on each answer in the result (answers[].choice) and the answers pages.
| Key | When |
|---|---|
index | One pick: single choice, yes or no, A or B, a reaction. A 1 to 5 rating reads 0 to 4. |
indexes | Pick several (multi choice), in option order. |
order | Ranking, best first. |
pair | Pairwise with three or more options: the two options shown; index is the one picked. |
ratings | Rate each: one rating from 1 to 5 per statement, in option order. |
The cohort hash
Cohort hash: the same value means the same kind of audience was asked (who, how many, which tier and targeting). It never identifies anyone. It is ch1_ and 16 hex characters, on every line and on the result as cohortHash. It also covers the question type, the language, an interest audience and its minimum grade, but never the words asked: two questions put to the same audience share it, so you can group their answers. Change who is asked and it changes. For a shared link, tier and targeting do not apply.