{"openapi":"3.1.0","info":{"title":"Minds Public API","version":"v1","description":"OpenAPI 3.1.0 spec for the Minds public API (https://getminds.ai/api/v1 / https://api.getminds.ai/v1). Generate a typed TypeScript client by running an OpenAPI generator (e.g. `openapi-typescript`) against `/_openapi.json`. Auth: send `Authorization: Bearer minds_…_key`; create keys in Settings → API Keys."},"servers":[{"url":"https://api.getminds.ai","description":"Production (api subdomain)"},{"url":"https://getminds.ai","description":"Production (apex)"}],"paths":{"/api/acp/checkout_sessions/{id}":{"get":{"responses":{"200":{"description":"OK"}},"operationId":"getAcpCheckout","summary":"Read an owned ACP checkout session","tags":["ACP"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"post":{"responses":{"200":{"description":"OK"}},"operationId":"updateAcpCheckout","summary":"Refresh an immutable hosted ACP checkout session","tags":["ACP"],"description":"Send an empty body. Billing details and discounts are updated through continue_url.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/acp/checkout_sessions/{id}/cancel":{"post":{"responses":{"200":{"description":"OK"}},"operationId":"cancelAcpCheckout","summary":"Cancel an owned, open ACP checkout session","tags":["ACP"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/acp/checkout_sessions/{id}/complete":{"post":{"responses":{"200":{"description":"OK"}},"operationId":"completeAcpCheckout","summary":"Check completion of an owned hosted ACP session","tags":["ACP"],"description":"Send an empty body. Returns requires_escalation with continue_url until Stripe confirms buyer checkout. Payment credentials are collected by Stripe.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/acp/checkout_sessions":{"post":{"responses":{"201":{"description":"ACP session, requiring buyer continuation."},"400":{"description":"Unsupported purchase or missing consent."},"401":{"description":"Minds authentication required."},"409":{"description":"Price or purchase changed."}},"operationId":"createAcpCheckout","summary":"Create an ACP hosted Stripe checkout","tags":["ACP"],"description":"One subscription or response-credit price per session. Subscription metadata requires explicit legalAcceptance. The buyer completes checkout at continue_url.","parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","maxLength":128,"pattern":"^[a-zA-Z0-9_-]+$"}},{"in":"header","name":"API-Version","schema":{"type":"string","enum":["2026-04-17"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["line_items","currency","capabilities"],"properties":{"line_items":{"type":"array","minItems":1,"maxItems":1,"items":{"type":"object","additionalProperties":false,"required":["id"],"properties":{"id":{"type":"string","pattern":"^price_[a-zA-Z0-9]+$"},"name":{"type":"string"},"unit_amount":{"type":"integer","minimum":0}}}},"currency":{"type":"string","enum":["usd","eur"]},"capabilities":{"type":"object","additionalProperties":true},"metadata":{"type":"object","additionalProperties":false,"properties":{"billingCountry":{"type":"string","maxLength":10},"quantity":{"type":"integer","minimum":1},"legalAcceptance":{"type":"object","additionalProperties":false,"required":["termsAccepted","withdrawalConsent"],"properties":{"termsAccepted":{"const":true},"withdrawalConsent":{"const":true}}}}}}}}}}}},"/api/v1/api-keys/{keyId}":{"delete":{"responses":{"204":{"description":"API key deleted. Empty body."},"400":{"description":"`API key ID is required` or `Invalid API key ID format` (not a well-formed cuid)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"No active subscription (`Forbidden`): API key access requires an active subscription. Please upgrade to the Starter or Pro plan."},"404":{"description":"`API key not found`: no key with this ID belongs to the authenticated account."}},"operationId":"deleteApiKey","summary":"Revoke an API key","description":"Permanently delete one API key owned by the authenticated account. The key stops authenticating immediately (the resolver cache is invalidated on delete). Use this to rotate credentials: create a replacement with `POST /v1/api-keys`, switch your integration over, then revoke the old key. Deleting the key used for the current request is allowed. Requires an active Premium or Team subscription.","tags":["API Keys"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"keyId","required":true,"description":"API key ID from `GET /v1/api-keys` (cuid: `c` followed by 24 lowercase alphanumerics).","schema":{"type":"string","pattern":"^c[a-z0-9]{24}$"}}]}},"/api/v1/api-keys":{"get":{"responses":{"200":{"description":"API keys ordered by `createdAt` descending.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeySummary"}},"example":[{"id":"clx1a2b3c4d5e6f7g8h9i0j1k","name":"prod","createdAt":"2025-12-10T12:00:00.000Z","lastUsedAt":"2025-12-10T13:00:00.000Z"}]}}},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"No active subscription (`Forbidden`): API key access requires an active subscription. Please upgrade to the Starter or Pro plan."}},"operationId":"listApiKeys","summary":"List API keys","description":"List metadata for every API key on the authenticated account, newest first. Secret key values are never returned; the raw key is shown exactly once, in the response of `POST /v1/api-keys`. Requires an active Premium or Team subscription.","tags":["API Keys"],"security":[{"ApiKeyAuth":[]}],"parameters":[]},"post":{"responses":{"201":{"description":"API key created. `key` is the raw secret and is only ever returned in this response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"},"example":{"id":"clx1a2b3c4d5e6f7g8h9i0j1k","name":"prod","createdAt":"2025-12-10T12:00:00.000Z","key":"minds_0000111122223333444455556666777788889999aaaabbbb"}}}},"400":{"description":"`name must be a string` (non-string, non-null `name`) or `name must be 100 characters or fewer` (after trimming)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"No active subscription (`Forbidden`: API key access requires an active subscription. Please upgrade to the Starter or Pro plan.) or `API keys are disabled for this SSO-linked account`."}},"operationId":"createApiKey","summary":"Create an API key","description":"Mint a new API key for the authenticated account and return its secret value exactly once. Store the `key` immediately; it cannot be retrieved again (`GET /v1/api-keys` returns metadata only). The body is optional: send `{ \"name\": \"prod\" }` to label the key, or no body at all for an unnamed key. Requires an active Premium or Team subscription. Accounts whose credentials are managed by an SSO identity link cannot mint API keys.","tags":["API Keys"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":["string","null"],"maxLength":100,"description":"Optional label shown in the key list and Settings UI. Whitespace is trimmed; an empty, null, or missing value stores the key unnamed (`name: null`)."}}},"examples":{"named":{"summary":"Labelled key","value":{"name":"prod"}},"unnamed":{"summary":"Unnamed key (empty body is also accepted)","value":{}}}}}},"parameters":[]}},"/api/v1/audiences/{audienceId}":{"delete":{"responses":{"204":{"description":"The Audience and its orphan-only member Minds were deleted."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Audience not found`: the Audience does not exist or the caller is not its owner."}},"operationId":"deleteAudience","summary":"Delete an Audience","description":"Permanently deletes an Audience. Owner only; collaborators and viewers receive 404. The deletion cascades to member Minds that the caller owns and that belong to no other Audience, so those Minds (with their training data and Study links) are removed too. Minds owned by other users, and Minds that are also members of another Audience, are kept. Remove Minds you want to keep with `DELETE /audiences/{audienceId}/members/{mindId}` first, or add them to another Audience.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}}]},"get":{"responses":{"200":{"description":"The Audience detail.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/AudienceDetail"}}}}}},"400":{"description":"`Audience ID is required` or `Invalid audience ID format` (the path parameter is not a UUID)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Audience not found`: the Audience does not exist or the caller cannot view it."}},"operationId":"getAudience","summary":"Get an Audience","description":"Returns one Audience with its member Minds (each with its cohort profile), the caller's role, the stored grounding, the source bundle (brief, adjustments, keywords, links, files), member-derived baseline distributions, and the transient recalibration state. Use it to inspect an Audience before attaching it to a Study, to poll `calibration.active` after `POST /audiences/{audienceId}/recalibrate`, or to watch member `profileImageUrl` values arrive after `regenerate-images`. Formations are not embedded; list them with `GET /audiences/{audienceId}/formations`. Readable by the owner, direct members, members of the owner's team when the Audience is team-shared, any authenticated caller when the Audience is public, and members of a Study that contains the Audience. Setting `isSharedWithTeam: true` lets every member of the owner's team open the Audience and read and chat with every Mind in it, even when those Minds are not shared individually; it grants no edit rights on the Minds. Explicit Audience members get the same read access. Only collaborators (owner, direct member, team member) receive the sharing fields `isSharedWithTeam`, `isLinkSharingEnabled` and `publicShareId`; public and Study-cascade viewers get `currentMemberRole: public_viewer`, and uploaded-file URLs in `sources` and `grounding.sources` are redacted for them.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"members","description":"Use preview for bounded display profiles without reviewed-field metadata; omitted preserves the complete legacy detail response.","schema":{"type":"string","enum":["preview"]}},{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}}]},"put":{"responses":{"200":{"description":"The updated Audience.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","name","mindCount","minds","createdAt","updatedAt","isPublic","isSharedWithTeam","isLinkSharingEnabled","publicShareId","currentMemberRole"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"mindCount":{"type":"integer","minimum":0},"minds":{"type":"array","items":{"$ref":"#/components/schemas/AudienceMindSummary"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isPublic":{"type":"boolean"},"isSharedWithTeam":{"type":"boolean"},"isLinkSharingEnabled":{"type":"boolean"},"publicShareId":{"type":["string","null"]},"currentMemberRole":{"type":"string","enum":["owner","admin","member","team_member"]}}}}}}}},"400":{"description":"`name is required` (missing or blank name), `Audience ID is required`, or `Invalid audience ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Audience not found`: the Audience does not exist or the caller has no edit access (public and Study-link viewers included)."}},"operationId":"updateAudience","summary":"Update an Audience name and sharing settings","description":"Renames an Audience and optionally changes its visibility. `name` is required on every call; `isPublic` and `isSharedWithTeam` are applied only when sent as booleans and left unchanged otherwise. `isLinkSharingEnabled` cannot be changed here (it is echoed in the response). Allowed for collaborators: the owner, direct members, and members of the owner's team when the Audience is team-shared. Only the owner may change `isSharedWithTeam` (403 `TEAM_SHARE_OWNER_ONLY` otherwise), and sharing requires the owner to be in a team (400 `TEAM_REQUIRED`). Public and Study-link viewers receive 404. Setting `isSharedWithTeam: true` lets every member of the owner's team open the Audience and read and chat with every Mind in it, even when those Minds are not shared individually; it grants no edit rights on the Minds. Explicit Audience members get the same read access. Setting `isPublic: true` lists the Audience in the marketplace and queues a cover image for it.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"description":"New Audience name; surrounding whitespace is trimmed. Required even when only sharing flags change."},"isPublic":{"type":"boolean","description":"List the Audience publicly. Anyone signed in can then open it and its Minds."},"isSharedWithTeam":{"type":"boolean","description":"Share with every member of the owner's team. Grants read-and-chat access to all member Minds; no edit rights on the Minds."}}},"examples":{"rename":{"value":{"name":"German SaaS buyers (2026)"}},"shareWithTeam":{"value":{"name":"German SaaS buyers","isSharedWithTeam":true}}}}}}}},"/api/v1/audiences/{audienceId}/collaborators/{userId}":{"delete":{"responses":{"200":{"description":"Removed.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid id, or the user is the owner (`COLLABORATOR_IS_OWNER`)."},"401":{"description":"Unauthorized."},"403":{"description":"The caller can see the Audience but does not manage its sharing (`COLLABORATORS_MANAGER_ONLY`)."},"404":{"description":"Audience not found or not visible to the caller, or the person is not a collaborator."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"removeAudienceCollaborator","summary":"Remove a collaborator from a Audience","description":"Removes the person's membership and revokes their invitations for this Audience in one step, so an old invitation link cannot restore access. Nobody is emailed. Only the Audience owner or a direct Audience admin may call it; the owner cannot be removed.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/collaborators":{"get":{"responses":{"200":{"description":"Collaborators of the Audience.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","required":["userId","email","name","role","joinedAt"],"properties":{"userId":{"type":"string","format":"uuid","description":"Pass to DELETE …/collaborators/{userId}."},"email":{"type":["string","null"],"format":"email"},"name":{"type":["string","null"]},"role":{"type":"string","description":"Role granted by the accepted invitation."},"joinedAt":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Invalid id."},"401":{"description":"Unauthorized."},"403":{"description":"The caller can see the Audience but does not manage its sharing (`COLLABORATORS_MANAGER_ONLY`)."},"404":{"description":"Audience not found or not visible to the caller."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"listAudienceCollaborators","summary":"List the people who accepted an invitation to a Audience","description":"Returns every collaborator of the Audience (people who accepted an email invitation), oldest first, without the owner. Pending invitations are listed by the invitations endpoints. Only the Audience owner or a direct Audience admin may call it; anyone else who can see the Audience gets 403.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/duplicate":{"post":{"responses":{"200":{"description":"Idempotent replay of the copy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedAudienceResponse"}}}},"201":{"description":"The new copy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedAudienceResponse"}}}},"400":{"description":"Invalid Audience id or body."},"401":{"description":"Authentication required."},"403":{"description":"The caller cannot edit this Audience, or the copy would exceed the plan's Mind or member allowance."},"404":{"description":"Audience not found."}},"operationId":"duplicateAudience","summary":"Duplicate an Audience","description":"Creates a private copy of an Audience you can edit: new, independent copies of every member Mind with their profiles, knowledge and embeddings, plus the grounding, sources, formations and finished validation history. Sharing, public links and running jobs are not copied. While the Audience is still being built the copy is its last good state (a member being rewritten is copied as the version it was trained as); copied members without a working version are retrained on their record. An optional idempotency key replays the same copy with status 200; a new copy returns 201.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"x-minds-idempotency-key","in":"header","required":false,"description":"Reuse for retries of the same duplication. Blank keys and keys longer than 128 characters are ignored.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Name of the copy. Defaults to \"<name> (copy)\"."}}}}}}}},"/api/v1/audiences/{audienceId}/export-download":{"get":{"responses":{"200":{"description":"Audience export artifact."}},"operationId":"downloadAudienceExport","summary":"Download an Audience export","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"kind","required":false,"schema":{"type":"string","enum":["brief","validation_report"]},"description":"The brief (default) or the validation report."},{"in":"query","name":"format","required":false,"schema":{"type":"string","enum":["pdf","md","docx","pptx","xlsx"]}}]}},"/api/v1/audiences/{audienceId}/export-status":{"get":{"responses":{"200":{"description":"Audience export status. `unavailable` for a validation report of an Audience with no scored validation."}},"operationId":"getAudienceExportStatus","summary":"Get Audience export status","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"kind","required":false,"schema":{"type":"string","enum":["brief","validation_report"]},"description":"The brief (default) or the validation report."},{"in":"query","name":"format","required":false,"schema":{"type":"string","enum":["pdf","md","docx","pptx","xlsx"]}}]}},"/api/v1/audiences/{audienceId}/export":{"post":{"responses":{"200":{"description":"Cached artifact or queued export job."},"400":{"description":"A format the requested kind does not offer."},"409":{"description":"No scored validation to report yet (`kind: validation_report`)."}},"operationId":"exportAudienceBrief","summary":"Export an Audience brief or validation report","description":"Generates the Audience brief (`kind: brief`, default; pdf, md, docx, pptx) or the validation report (`kind: validation_report`; pdf, md, docx, xlsx): every scored validation with the overall score calculation, every KPI with its 95% interval, per-question answer shares, the composition check and provenance. The validation report needs edit access to the Audience and at least one scored validation (409 `VALIDATION_REPORT_UNAVAILABLE` otherwise). A cached artifact returns at once; otherwise the job is queued and polled through export-status.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"format":{"type":"string","enum":["pdf","md","markdown","docx","pptx","xlsx"]},"kind":{"type":"string","enum":["brief","validation_report"]},"force":{"type":"boolean"}}}}}}}},"/api/v1/audiences/{audienceId}/filter-attributes":{"get":{"responses":{"200":{"description":"Facets and matching Minds.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["totalMinds","attributedMinds","matchCount","mindIds","facets","truncated"],"properties":{"totalMinds":{"type":"integer","minimum":0,"description":"Minds in the Audience that were read."},"attributedMinds":{"type":"integer","minimum":0,"description":"Minds with at least one filter attribute. Zero means the Audience carries no filter attributes."},"matchCount":{"type":"integer","minimum":0},"mindIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Matching Minds, sorted by ID."},"truncated":{"type":"boolean"},"facets":{"type":"array","items":{"type":"object","required":["key","values","unknownCount"],"properties":{"key":{"type":"string","enum":["perspective","industry","role","country","companySize","technology","businessModel"]},"values":{"type":"array","maxItems":200,"items":{"type":"object","required":["value","count"],"properties":{"value":{"type":"string"},"count":{"type":"integer","minimum":0}}}},"unknownCount":{"type":"integer","minimum":0}}}}}}}}}}},"400":{"description":"Invalid audience ID or `filters` (not JSON, unknown attribute, wrong value type, too long)."},"401":{"description":"Missing or invalid API key."},"404":{"description":"`Audience not found`: it does not exist or the caller cannot view it."},"500":{"description":"Internal server error."}},"operationId":"filterAudienceMinds","summary":"Filter an Audience's Minds by their filter attributes","description":"Returns the filter attributes present in an Audience (perspective, industry, role, country as ISO 3166-1 alpha-2, companySize, technology, businessModel) with per-value counts, and the Minds matching `filters`. Values of one attribute are alternatives (OR); attributes combine (AND); `null` selects Minds without a value for that attribute (\"not known\"). Each facet counts the Minds that match every other attribute's selection, so a count is the number of Minds the result would hold with that value picked. Pass the returned `mindIds` to `POST /audiences` (`mindIds`) to turn the selection into a new Audience. Readable by anyone who can view the Audience; otherwise 404. At most 5,000 Minds are read per request (`truncated` reports a larger Audience). Responses are private and non-cacheable.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"filters","in":"query","required":false,"description":"URL-encoded JSON object mapping attribute keys to arrays of values or null, e.g. `{\"industry\":[\"Labels\"],\"country\":[\"DE\",null]}`. At most 8,192 characters and 50 values per attribute. Omit for the unfiltered facets.","schema":{"type":"string","maxLength":8192}}]}},"/api/v1/audiences/{audienceId}/follow":{"delete":{"responses":{"200":{"description":"Audience unfollowed."},"401":{"description":"Unauthorized."}},"operationId":"unfollowAudience","summary":"Unfollow a public Audience","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string"}}]},"post":{"responses":{"200":{"description":"Audience followed."},"401":{"description":"Unauthorized."},"404":{"description":"Public Audience not found."}},"operationId":"followAudience","summary":"Follow a public Audience","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/v1/audiences/{audienceId}/formations/{formationId}":{"delete":{"responses":{"204":{"description":"The Formation was deleted."},"400":{"description":"`Audience ID is required`, `Invalid audience ID format`, `Formation ID is required`, or `Invalid formation ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Formation not found`: the Audience is not viewable, or the Formation does not exist, is already deleted, or is not mutable by the caller."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"deleteFormation","summary":"Delete a Formation","description":"Soft-deletes a Formation so it disappears from listings while Study messages that referenced it keep rendering. Collaborators may delete shared Formations and their own private ones; other viewers may delete only Formations they created privately. A Formation the caller cannot mutate yields 404.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"formationId","in":"path","required":true,"description":"Formation ID (UUID).","schema":{"type":"string","format":"uuid"}}]},"get":{"responses":{"200":{"description":"The Formation detail.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Formation"}}}}}},"400":{"description":"`Audience ID is required`, `Invalid audience ID format`, `Formation ID is required`, or `Invalid formation ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Formation not found`: the Audience is not viewable, or the Formation does not exist, was deleted, or is private to another viewer."},"500":{"description":"Unexpected storage failure or invalid persisted detail; internal details are redacted."}},"operationId":"getFormation","summary":"Get a Formation with its subgroups and members","description":"Returns one Formation: build status, live build progress, the stored hypothesis, and the real subgroups with their member assignments and confidences. Poll this after `POST /formations`, `POST /formations/preview` acceptance, or `recompute` until `status` is `ready` or `failed`; while `building`, `subgroups` may be empty and `hypothesis.subgroups` describes the proposed buckets. Visible to any Audience viewer for shared Formations and to the creator for private ones. Responses are private and non-cacheable. Stored diagnostics are omitted; failed builds expose only safe failure reasons. Invalid legacy proposals become an empty object, malformed building progress becomes null, and ready builds always return null progress.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"formationId","in":"path","required":true,"description":"Formation ID (UUID).","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/formations/{formationId}/recompute":{"post":{"responses":{"200":{"description":"The rebuild was queued.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["building","ready","failed"],"description":"Usually `building`; already terminal when the build ran inline."}}}}}}}},"400":{"description":"`Audience ID is required`, `Invalid audience ID format`, `Formation ID is required`, or `Invalid formation ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Formation not found`: the Audience is not viewable, or the Formation does not exist, is deleted, or is not mutable by the caller."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"recomputeFormation","summary":"Re-sort the current members into an existing Formation","description":"Re-classifies the Audience's current members against the Formation's stored hypothesis and swaps the subgroups in place, without a new preview. Use it after members were added or recalibrated, or to recover a Formation stuck in `building` or `failed`. Flips `status` to `building` and returns immediately; poll `GET /audiences/{audienceId}/formations/{formationId}`. Same mutability rules as delete: collaborators for shared Formations, creators for private ones.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"formationId","in":"path","required":true,"description":"Formation ID (UUID).","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/formations":{"get":{"responses":{"200":{"description":"Visible Formations.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/FormationSummary"}},"pagination":{"type":"object","required":["total","limit","offset","hasMore","nextOffset"],"properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0},"hasMore":{"type":"boolean"},"nextOffset":{"type":["integer","null"],"minimum":0}}}}}}}},"400":{"description":"Invalid limit/offset, `Audience ID is required` or `Invalid audience ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Formation not found`: the Audience does not exist or the caller cannot view it (the message deliberately does not reveal which)."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"listFormations","summary":"List the Formations of an Audience","description":"Lists the Formations (persisted segmentations) visible to the caller on an Audience: shared Formations plus the caller's own private ones, newest first (ID breaks timestamp ties), each with its subgroups and membership counts. Soft-deleted Formations are excluded. Anyone who can view the Audience may call this. Opening the list also seeds the canonical default and grounding-derived Formations for collaborators and re-queues stalled builds, so rows may come back with `status: building`; poll `GET /audiences/{audienceId}/formations/{formationId}` until they are `ready` or `failed`. Only one row per auto dimension is returned (ready preferred over building over failed). De-duplication precedes pagination: limit defaults to 100 and cannot exceed 100; offset defaults to 0. Follow pagination.nextOffset while hasMore is true. Only offset 0 performs seeding/recovery, attempting at most 100 oldest pending builds. Individual recovery failures do not prevent attempts for other selected builds or a successful list response. Pages are individually consistent; concurrent writes can shift later offsets.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"maximum":9007199254740991,"default":0}}]},"post":{"responses":{"200":{"description":"The Formation was created and its build queued.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","name","status"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["building","ready","failed"]}}}}}}}},"400":{"description":"`Invalid JSON body` or `Invalid Formation input` (needs non-empty `intent` and 2 to 15 uniquely identified and labelled subgroups with non-empty `id`, `label`, `definition`; optional `name` must be a string), `Audience has no members to categorize`, `FORMATION_CAP` (more than 1000 members), `Audience ID is required`, or `Invalid audience ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Formation not found`: the Audience does not exist, the caller cannot view it, or the created Formation was deleted before acknowledgement."},"413":{"description":"JSON request body exceeds 64 KiB."},"500":{"description":"Unexpected storage failure; internal details are redacted."}},"operationId":"createFormation","summary":"Create a Formation from an accepted hypothesis","description":"Creates a Formation from a hypothesis (the subgroup proposal returned by `POST /audiences/{audienceId}/formations/preview`, optionally edited) and starts sorting the Audience's members into its subgroups. Returns immediately with `status: building`; poll `GET /audiences/{audienceId}/formations/{formationId}` until `ready` or `failed`. When the build runs inline the returned status may already be terminal. Any Audience viewer may create a Formation: collaborators create `shared` Formations, other viewers create ones private to themselves. The Audience must have at least one member and at most 1000. JSON bodies are limited to 64 KiB. Hypothesis text fields are trimmed and must be non-empty; subgroup IDs and labels must be unique. Reserved auxiliary IDs (unanswered, __unanswered, __other) cannot be used. User-created Formations require at least two populated primary buckets to become ready. All responses are private and non-cacheable.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["hypothesis"],"properties":{"hypothesis":{"$ref":"#/components/schemas/FormationHypothesis"},"name":{"type":"string","description":"Optional display name. Defaults to a compact form of `hypothesis.intent`."}}},"examples":{"byGender":{"value":{"name":"By gender","hypothesis":{"intent":"Audience by gender","subgroups":[{"id":"woman","label":"Female","definition":"Members who identify as women."},{"id":"man","label":"Male","definition":"Members who identify as men."}]}}}}}}}}},"/api/v1/audiences/{audienceId}/formations/preview":{"post":{"responses":{"200":{"description":"The proposed hypothesis, either as one JSON document or as an NDJSON event stream.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["memberCount","softWarn","hardCapExceeded","phase","hypothesis"],"properties":{"memberCount":{"type":"integer","minimum":0},"softWarn":{"type":"boolean","description":"True from 50 members: builds take noticeably longer."},"hardCapExceeded":{"type":"boolean","description":"True above 1000 members: `POST /formations` will refuse with `FORMATION_CAP`."},"phase":{"type":"string","enum":["hypothesizing"]},"hypothesis":{"$ref":"#/components/schemas/FormationHypothesis"}}}}}},"application/x-ndjson":{"schema":{"type":"object","description":"One event per line.","required":["type"],"properties":{"type":{"type":"string","enum":["meta","status","subgroups","error","done"]},"data":{"description":"`meta`: `{ memberCount, softWarn, hardCapExceeded }`; `status`: `{ phase: \"hypothesizing\" }`; `subgroups`: a FormationHypothesis. Absent on `error` and `done`.","oneOf":[{"type":"object","required":["memberCount","softWarn","hardCapExceeded"],"properties":{"memberCount":{"type":"integer"},"softWarn":{"type":"boolean"},"hardCapExceeded":{"type":"boolean"}}},{"type":"object","required":["phase"],"properties":{"phase":{"type":"string","enum":["hypothesizing"]}}},{"$ref":"#/components/schemas/FormationHypothesis"}]},"error":{"type":"string","description":"Failure message; only on `error` events."}}}}}},"400":{"description":"Invalid JSON or preview input, malformed priorHypothesis, missing Audience ID or invalid Audience ID format."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Formation not found`: the Audience does not exist or the caller cannot view it."},"406":{"description":"Accept does not allow either supported UTF-8 JSON or NDJSON representation."},"413":{"description":"JSON request body exceeds 64 KiB."},"500":{"description":"Storage/setup failures return a generic HTTP 500 before either response mode starts. Model failures and invalid model proposals return Failed to propose subgroups: HTTP 500 in JSON mode, or an in-band error followed by done with HTTP 200 once NDJSON has started. Internal error details are never returned."}},"operationId":"previewFormation","summary":"Propose Formation subgroups without creating anything","description":"Asks the model to propose a subgroup hypothesis for this Audience from a free-text request (e.g. \"split by purchase frequency\"). Nothing is persisted; pass the returned hypothesis (edited if you like) to `POST /audiences/{audienceId}/formations` to build it, or re-post with `priorHypothesis` set to the previous proposal to request a rework. Any Audience viewer may call this. Optional JSON bodies are limited to 64 KiB; userInput is a string of at most 2000 trimmed characters. Invalid supplied priorHypothesis values return 400. Responses, including refusals, are private and non-cacheable. Disconnecting the request or cancelling the stream aborts model generation. Returned proposals satisfy the creation input contract. Send `Accept: application/json` to receive one JSON document. Accept quality weights, wildcards, and media parameters are respected; when neither JSON nor NDJSON is acceptable the route returns 406 before generation. With no Accept preference the response is a newline-delimited JSON stream (`application/x-ndjson`) of `{ type, data }` events in the order `meta`, `status`, `subgroups`, `done`, with failures reported in-band as `{ type: \"error\", error }` followed by `done`.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"Accept","in":"header","required":false,"description":"Choose application/json or application/x-ndjson, optionally with quality weights. Both use UTF-8. Missing Accept defaults to NDJSON; no acceptable type returns 406.","schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"userInput":{"type":"string","maxLength":2000,"description":"What to split by. Defaults to \"Split this audience into meaningful subgroups.\""},"priorHypothesis":{"oneOf":[{"$ref":"#/components/schemas/FormationHypothesis"},{"type":"null"}],"description":"The previous proposal when asking for a rework. Null or omitted means no prior proposal; malformed values return 400."}}},"examples":{"first":{"value":{"userInput":"Split by how often they buy online"}}}}}}}},"/api/v1/audiences/{audienceId}/members":{"post":{"responses":{"200":{"description":"The Minds were added (or were already members).","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["added"],"properties":{"added":{"type":"integer","minimum":1,"description":"Number of distinct Mind IDs in the request."}}}}}}}},"400":{"description":"Invalid JSON/object input, more than 1,000 supplied IDs, invalid Mind UUIDs, `mindId or mindIds is required`, `At least one Mind ID is required` (empty array), a retired field name (rejected with a message naming its replacement), `Audience ID is required`, or `Invalid audience ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"Adding these Minds would exceed the plan's Audience member cap. `statusMessage` names the plan and the limit; `data` carries the plan-limit envelope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanLimitError"}}}},"404":{"description":"`Audience not found` (missing, or the caller is not the owner), or `One or more Minds not found or not accessible` (a Mind is neither owned by the caller nor public). Nothing is added in either case."},"413":{"description":"JSON body exceeds 64 KiB, including ignored fields."},"500":{"description":"Unexpected storage or plan-resolution failure. Internal details are not returned."}},"operationId":"addAudienceMembers","summary":"Add Minds to an Audience","description":"Adds one Mind (`mindId`) or several Minds (`mindIds`) to an Audience. Requires a JSON object within 64 KiB and at most 1,000 supplied IDs before deduplication. Owner only; collaborators and viewers receive 404. Membership capacity and authorization are rechecked in a single transaction; concurrent additions cannot both consume the last available slot. Responses, including refusals, are private and non-cacheable. Unexpected storage or plan-resolution failures return a generic 500. Every Mind must be owned by the caller or public, otherwise nothing is added. Minds that are already members are ignored, so the call is idempotent; `added` reports the number of distinct IDs in the request, not the number of new memberships. Newly added Minds are sorted into the Audience's ready Formations in the background, and default Formations are seeded if the Audience had none. In the background each added Mind is also placed on the Audience's charts from the facts its own record holds (never invented; its own record is not changed), the Audience's allocation audit is measured again on the current members, and members whose training failed are retrained. Use `mindIds` rather than the retired `mindId`/`mindIds` fields.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Send either `mindId` or `mindIds`. When both are present `mindId` wins.","oneOf":[{"required":["mindId"],"properties":{"mindId":{"type":"string","format":"uuid","description":"A single Mind to add; mindIds is ignored when this is supplied."}}},{"required":["mindIds"],"not":{"required":["mindId"]},"properties":{"mindIds":{"type":"array","minItems":1,"maxItems":1000,"items":{"type":"string","format":"uuid"},"description":"Several Minds to add. Duplicate IDs are deduplicated after the size check."}}}]},"examples":{"single":{"value":{"mindId":"6f1d2c3a-1111-4222-8333-444455556666"}},"bulk":{"value":{"mindIds":["6f1d2c3a-1111-4222-8333-444455556666","0a9b8c7d-2222-4333-8444-555566667777"]}}}}}}}},"/api/v1/audiences/{audienceId}/members/{mindId}":{"delete":{"responses":{"204":{"description":"The Mind is no longer a member of the Audience."},"400":{"description":"`Audience ID is required`, `Invalid audience ID format`, `Mind ID is required`, or `Invalid mind ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Audience not found`: the Audience does not exist or the caller is not its owner."},"500":{"description":"Unexpected storage failure; internal details are not returned."}},"operationId":"removeAudienceMember","summary":"Remove a Mind from an Audience","description":"Removes one Mind from an Audience and from every Formation subgroup on that Audience. The Mind itself is not deleted. Owner only; collaborators and viewers receive 404. Ownership is rechecked under a transaction lock; membership and subgroup cleanup commit together. Responses are private and non-cacheable, with generic 500 errors for unexpected storage failures. Removing a Mind that is not a member is a no-op that still returns 204. In the background the Audience's allocation audit is measured again on the remaining members, and members whose training failed are retrained.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"mindId","in":"path","required":true,"description":"Mind ID (UUID).","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/progress":{"get":{"responses":{"200":{"description":"Current member progress snapshot.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","required":["audienceId","members","readiness","reconciledAt"],"properties":{"audienceId":{"type":"string","format":"uuid"},"members":{"type":"array","items":{"type":"object","required":["mindId","update"],"properties":{"mindId":{"type":"string","format":"uuid"},"update":{"type":"object","description":"Member progress. `readyToChat`, `trainingStatus`, `trainingError` and `beingRepaired` follow `GET /minds/{mindId}/training`.","properties":{"readyToChat":{"type":"boolean","description":"The member can answer: its profile and system prompt exist."},"beingRepaired":{"type":"boolean","description":"Present and true while the member cannot answer yet because its last training attempt failed and it is retrained automatically (`trainingStatus: queued`)."},"learningInBackground":{"type":"boolean","description":"The member can answer and is still learning from its sources in the background."},"fullyTrained":{"type":"boolean","description":"The member can answer and its background knowledge step has settled."},"trainingStatus":{"type":"string","enum":["queued","running","completed","failed"]}}}}}},"readiness":{"type":"object","required":["total","ready","training","failed","isReady","learning","fullyTrained"],"properties":{"total":{"type":"integer","description":"Members counted."},"ready":{"type":"integer","description":"Members that can chat (`readyToChat`)."},"training":{"type":"integer","description":"Members that cannot chat yet and are still training."},"failed":{"type":"integer","description":"Always 0: a member whose last training attempt failed is being prepared again and counts in `training` (its member update reports `trainingStatus: queued` and `beingRepaired`). Kept for existing clients."},"isReady":{"type":"boolean","description":"Every member can chat: the Audience is ready."},"startsNow":{"type":"boolean","description":"A Study started now runs at once: nothing is training, and the members that failed training for good are either few enough to leave out (at least one Mind and at least half of the members still answer) or can no longer be retrained automatically. Otherwise it waits for them to be retrained."},"leftOut":{"type":"integer","description":"Members still being prepared that a Study started now runs without; they join once they are ready."},"learning":{"type":"integer","description":"Ready members still learning from their sources in the background."},"fullyTrained":{"type":"boolean","description":"Every member can chat and none is still learning."}}},"research":{"type":"object","description":"Where the Audience's research stands. Never a reason to wait: the Audience is usable while it researches.","properties":{"phase":{"type":"string","enum":["usable","researching","researched"],"description":"`researching`: background web research is running (or waiting for a run to end before it updates the members). `researched`: done, or finished at creation. `usable`: it failed; the Audience stays on its first phase."},"status":{"type":"string","nullable":true,"enum":["queued","running","completed","failed"]},"stage":{"type":"string","nullable":true,"enum":["researching","waiting_for_runs","recalibrating","done"],"description":"`waiting_for_runs`: research is done and waits for a Study run or validation using these Minds to end before the members change."},"progress":{"type":"integer","minimum":0,"maximum":100},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"outcome":{"type":"object","nullable":true,"description":"What the research changed: `chartsAdded`, `sourcesAdded`, `dimensionsImproved` ([{ dimension, from, to }]), `membersRecalibrated`, `coverage` counts, `applied`, and for Go deeper `topics` ([{ topic, status: added | already_covered | not_found, chart?, evidence? }]).","additionalProperties":true}}},"coverage":{"type":"object","nullable":true,"description":"How each relevant standard dimension is covered now.","properties":{"dimensions":{"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string"},"status":{"type":"string","enum":["sourced","proxy","assumed","missing"]},"distribution":{"type":"string"}}}},"counts":{"type":"object","properties":{"sourced":{"type":"integer"},"proxy":{"type":"integer"},"assumed":{"type":"integer"},"missing":{"type":"integer"}}}}},"reconciledAt":{"type":"integer","description":"Server time of this snapshot, in epoch milliseconds."}}}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Audience not found."}},"operationId":"getAudienceProgress","summary":"Get the current creation progress for an Audience","description":"One read of every member's training state plus the Audience rollup. The Audience is ready when `readiness.isReady` is true: every member reports `readyToChat`, so it can be chatted with and a Study can run on it. `readiness.startsNow` says whether a Study started now runs at once even though some members failed training for good: it then runs without `readiness.leftOut` of them. Members keep learning from their sources in the background after that: `readiness.learning` counts the ready members whose knowledge step (a wider source collection, then a system prompt rebuilt from it) is still running, and `readiness.fullyTrained` turns true once none is. The Audience's own research continues in the background too: a new Audience stands first on what is already known (the evidence pool, your material and stated assumptions), and `research.phase` is `researching` while its web research runs, `researched` once it has been merged and the members recalibrated (between runs, never under one), `usable` if it failed and the Audience stays on its first phase. `coverage` says how each relevant standard dimension is covered: `sourced`, `proxy`, `assumed` or `missing`. Automatic validation of a new Audience waits for `fullyTrained` and for its research; nothing else does.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/v1/audiences/{audienceId}/recalibrate":{"post":{"responses":{"200":{"description":"Replay of a terminal operation. data.operation retains its completed result or failed error; no work is repeated.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["operation"],"properties":{"operation":{"type":"object","description":"The retained receipt with status completed or failed, result and error."}}}}}}}},"202":{"description":"Accepted durable recalibration (`data.operation`) or Go deeper research (`data.research`). Follow statusUrl or progressUrl.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","oneOf":[{"required":["operation"]},{"required":["research","progressUrl"]}],"properties":{"operation":{"type":"object","description":"Durable receipt: id, requestKey, status (queued/running/completed/failed), progress, statusUrl, result and error. Poll statusUrl for the grounding and member counts."},"research":{"type":"object","required":["jobId","phase","status","stage","progress"],"properties":{"jobId":{"type":"string","format":"uuid","description":"The background research job."},"phase":{"type":"string","enum":["researching"]},"status":{"type":"string","enum":["queued"]},"stage":{"type":"string","enum":["researching"]},"progress":{"type":"integer","minimum":0,"maximum":100}}},"progressUrl":{"type":"string","description":"The Audience progress read (`GET /audiences/{audienceId}/progress`) whose `research` follows this job."}}}}}}}},"400":{"description":"`Invalid recalibrate payload` (schema violation), `Invalid distributions payload` (selection mode produced no usable distributions), `Audience ID is required`, or `Invalid audience ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"An additive instruction with an explicit count exceeds the plan's Audience member cap, the Audience is already at the cap, or the plan's overall Mind quota would be exceeded. `data` carries the plan-limit envelope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanLimitError"}}}},"404":{"description":"`Audience not found`: the Audience does not exist or the caller is not its owner."},"409":{"description":"Ten edits of this Audience are already waiting (`data.code: RECALIBRATION_IN_PROGRESS`).","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer","enum":[409]},"statusMessage":{"type":"string"},"data":{"type":"object","properties":{"code":{"type":"string","enum":["RECALIBRATION_IN_PROGRESS"]}}}}}}}},"413":{"description":"The recalibration request exceeds 32 MiB."},"422":{"description":"Research mode, only for an Audience without saved charts or a full `query` override: `Could not find sufficient scientific data to ground this audience. Try a more specific description.` or, for a `requestedDistribution` no chart can answer for these people, code `AUDIENCE_DISTRIBUTION_NOT_APPLICABLE`. An Audience with saved charts keeps them instead, and a requested chart that cannot be made (it does not divide these people, or the model was unavailable; the latter is researched again in the background) is left out while the rest of the edit applies (`result.requestedTopics[].status: not_found`). A newly attached file whose reading cannot be resolved still fails with its own 422. A requested chart the Audience already has (the topic is measured by an existing chart) is not refused: the run completes with that chart first and `result.requestedTopics[].status: already_covered`; a new chart reports `added`; selection mode on an Audience without stored grounding: `This audience has no grounding to recalibrate. Run a research recalibration first.`"},"500":{"description":"The run failed after it started; the calibration marker is cleared so a retry is possible."},"502":{"description":"Only for an Audience without saved charts, or a full `query` override: research is unavailable and no first-party distributions can be used. An edit of an Audience with saved charts never fails on research: the saved charts stand and research runs again in the background after the edit."},"503":{"description":"Go deeper could not be queued, or its instruction could not be read (`AUDIENCE_EDIT_UNREAD`); nothing changed. Retry shortly."}},"operationId":"recalibrateAudience","summary":"Recalibrate an Audience's grounding and members","description":"Refreshes the stored grounding of a saved Audience and re-allocates its members to the resulting distributions. Owner, or confirmed Minds staff with existing direct Audience admin collaboration or an active owner-issued support grant, for composition amendments only (no growth, new sources, Go deeper or shared-Mind waiver). Support grants are managed under `/audiences/{audienceId}/support`. `deepen` (Go deeper) runs in the background and returns 202 at once with `data.research` (`jobId`, `phase: researching`) and `data.progressUrl`: it researches what the Audience still lacks (every standard dimension its coverage reports missing or assumed, plus `deepen.topics`) with the whole evidence pool and the coverage check, adds it to the saved grounding (every chart the Audience has stays; a chart gives way only to stronger evidence for the same question, or for the dimension it stands for), and recalibrates the members through the same step as any recalibration, between Study runs and validations, never under one (members keep answering with their previous version until their retrain lands). Follow it on `GET /audiences/{audienceId}/progress`: `research.phase` is `researching` until `researched`, `research.stage` moves researching → waiting_for_runs → recalibrating → done, and `research.outcome` reports the charts and sources added, the dimensions improved, the members recalibrated and, per requested topic, whether a chart was `added` (with its evidence tier), `already_covered` or `not_found`. Asked while the Audience's background research runs, it is queued behind that research and starts when it finishes; an active or waiting edit never blocks it (its job waits for the edit before it changes members) (`data.research.queuedBehindRunningResearch: true`); topics asked again before it starts join it. `sources` and `instruction` sent with it join the Audience's source bundle first. Two modes otherwise: research mode (default) re-runs deep research from the persisted brief, every earlier adjustment and the optional `instruction`, `sources` and `requestedDistribution`, or from `query` as a full override; selection mode (`distributions` present) skips research and only replaces the active distribution set, keeping the stored sources and review universe. In research mode the instruction is classified first: an adjustment (\"make men 40%\", \"now they are all vegan\", \"only 50 to 60 years old\") re-allocates the existing roster and rebuilds or evolves the members whose new segment contradicts who they are, while an additive instruction (\"and now add 10 African consumers\") keeps the existing members untouched and creates new ones within the plan's member cap. Facts the instruction states for the added people (\"add a CEO\") are held by every one of them: when each is already a segment of the Audience's charts the members are added on those charts without new research, otherwise research runs first. Those facts are held through every consistency repair of the new member (its other facts are redrawn around them, and a dealt value that contradicts one is dropped), and every chart stating the same fact (a translated copy) is pinned to the same value. The completed result lists them in `addedMinds` (id, name, role, description, the `requested` segments and the segments each `held`), with `requestedMembers` (how many were asked for) and `growthNotes` (what could not be done as asked, e.g. fewer members or a request that could not be read), so a run that adds fewer or no members says so. A stated total for the same people (\"make it 10\", \"reduce it to 10 people\", \"verkleinere auf 10 Personen\", read again independently and resized only when both readings state the same number; \"remove 5 members\" counts from the current size) resizes without research or retraining: a smaller total keeps the members whose facts best keep the Audience's target shares, always keeping members the requester listed or names to keep (\"keep Anna Schmidt\") and, before others, members an earlier edit added on request and members matching what the instruction says to keep (\"keep the CEO\"), always removing members it names to remove (\"drop Anna\"), and removes the others from this Audience only, their Minds staying in the library, and the allocation audit is measured on who stays; a larger total adds members exactly like \"N more\"; asking for a copy or version (\"a 10-person version\") leaves this Audience unchanged and creates a copy holding the selected members (a larger copy then grows through its own recalibration operation). An instruction that also asks for something else (\"make it 10 and add an income chart\") runs the resize first and the rest as the next part of the same operation (on a copy, in the copy's own operation). A model reads the parts of the instruction (the size, a copy, each other edit, members named to keep or remove, what to keep) and every part is anchored on words the instruction contains; no word list, capitalisation or word overlap decides it, in any language. Names are matched to the roster by a model: a name several members carry (\"Daniel\" with two Daniels) keeps or removes none of them and `resize.notes` says so; a name no member carries is noted too. Wording that only preserves (\"do not change their facts\", \"keep the removed Minds in my library\") is never a next part: nothing is researched or retrained for it. A next part that adds members without a stated count after a resize (\"make it 10 and add more Swiss\") reshapes the members kept instead of adding any. An additive instruction that also asks for something else (\"20 more, and make women 60%\") adds the members on the words asking for them and runs the rest as the next part, once; such instructions are never refused. When the instruction (or a part, a tie-break or the named members) cannot be read in full, the operation changes nothing and is retried automatically (its error code `AUDIENCE_EDIT_UNREAD` shows while it is queued again); a reading is never guessed or applied in part. A model also reads which share changes name a chart the Audience has (by its number in the Audience's chart list) and which charts are new, with the shares stated for them: a new chart's own shares (\"add a pets chart at 60/40\") never count as changing the existing targets, so \"refresh the sources but keep the shares, and add a pets chart at 60/40\" keeps them, while a share change on an existing chart (\"make women 55%\") is applied. The completed result reports `resize` (`mode` in_place or copy, the resized `audienceId`, `previousSize`, `size`, `kept`, `removed`, the average gap to the target shares before and after as `fit`, and `notes`). Without `deepen`, acceptance returns 202 immediately with `data.operation`; research and roster changes run on the processor. Poll its `statusUrl` or `GET /audiences/{audienceId}` (`calibration.operation`) for the retained result or terminal error. Send a stable `requestKey` or `Idempotency-Key` on retries: the same key and input replay the same operation, even after completion; changed input with that key returns 409. Member training continues after the roster change. Poll `GET /audiences/{audienceId}/progress` for per-member training and `GET /audiences/{audienceId}` for `calibration.active`. Only one recalibration runs per Audience at a time: an edit accepted while another is active or waiting is queued behind it and runs after it, in order (`operation.waiting.for: earlier_edit`); at most 10 may wait, and one still waiting after 24 hours fails with `AUDIENCE_EDIT_QUEUE_TIMEOUT`. Because recalibration rewrites the members' profiles and knowledge globally, members that also belong to other Audiences are copied into this Audience right before the members change (the same person, knowledge, training, team sharing and per-Mind access, with a new Mind id; protective copies do not count against the plan's Mind quota) so the other Audiences stay unchanged; the result lists each original and its copy in `copiedSharedMinds`. Send `allowSharedMinds: true` to rewrite them in place everywhere instead. Members owned by someone else (a Marketplace Mind, another user's or a teammate's) are always copied the same way before an edit rewrites them, whatever `allowSharedMinds` says, so another owner's Mind is never changed and the edit is never refused for it; these copies do not count against the Mind quota either. While a Study run is answering with these members the operation waits (status `queued`, `operation.waiting` names `study_run` and the `studyIds`) and applies the edit when the run has finished, since rewriting them mid-run changes who answers it; after 24 hours of waiting it fails with `STUDY_RUN_USES_MINDS`. Additive runs never wait. A stated addition larger than 50 members (within the plan's member cap; a stated count over the cap is refused with the plan limit) is added in parts of at most 50, one after another in the same operation, and the result totals them. When a model reading the edit (its intent, a count or a size, or the members' consistency) is unavailable, or research fails for an edit that changes who belongs (a new population, eligibility rule or bound, which the saved charts cannot stand in for), the operation stays `queued` with `operation.waiting.for: reader`, leaves the Audience as it was, and tries again on a growing interval (up to 24 hours) instead of failing; any other edit whose research fails is applied to the saved charts.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}},{"name":"Idempotency-Key","in":"header","required":false,"description":"Stable retry key; must match requestKey when both are supplied.","schema":{"type":"string","minLength":1,"maxLength":128}}],"requestBody":{"description":"Optional JSON request, up to 32 MiB. Empty input reruns research using saved sources.","required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"requestKey":{"type":"string","minLength":1,"maxLength":128,"description":"Stable retry key. Reuse with identical input to retrieve the same operation."},"query":{"type":"string","maxLength":4000,"description":"Research mode. Full override of the research query; the persisted brief and adjustments are ignored and nothing is persisted for replay."},"instruction":{"type":"string","maxLength":4000,"description":"Research mode. Adjustment appended to the replayed brief, e.g. \"add an income distribution\" or \"skew younger\". Persisted so later recalibrations replay it (additive instructions are stored declaratively)."},"requestedDistribution":{"type":"string","minLength":1,"maxLength":120,"description":"Research mode. Topic of exactly one distribution to add. Guaranteed to materialise (as an assumed-evidence axis when research finds no data); the existing axes and targets are preserved."},"sources":{"type":["object","null"],"description":"Research mode. Extra user sources, persisted to the Audience's source bundle and cited by the research run. Each list holds at most 20 entries.","properties":{"files":{"type":"array","maxItems":20,"items":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string","maxLength":300},"url":{"type":"string","maxLength":2000,"description":"URL of an already uploaded file."}}}},"links":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":2000}},"keywords":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":200}}}},"distributions":{"type":"array","maxItems":500,"description":"Selection mode. The complete active distribution set after a select/deselect edit of the saved review universe. Presence of this field (even empty) selects selection mode. Exact shares: to set a chart to e.g. 70% Female / 30% Male, send that chart with those `pct` values. They become the person's targets (the chart keeps its evidence and reads \"Set by you\"), the members are re-allocated to them, and no research runs.","items":{"$ref":"#/components/schemas/GroundingDistribution"}},"allowSharedMinds":{"type":"boolean","description":"Rewrite members shared with other Audiences in place, there too. Without it they are copied into this Audience first and the other Audiences stay unchanged."},"then":{"type":"array","maxItems":4,"description":"More parts of the same Rework, applied in order by this one operation after the first (for example exact chart edits, then an instruction, then \"20 more\"). Each item takes `query`, `instruction`, `requestedDistribution`, `sources`, `distributions` and `allowSharedMinds` like the top level. A part that fails stops the rest; the failure's `data.failedPart` names it (0-based). Not combinable with `deepen`.","items":{"type":"object"}},"deepen":{"type":"object","description":"Go deeper: research what the Audience still lacks (its missing and assumed standard dimensions) plus `topics`, and add it. Not combinable with `distributions`, `query` or `requestedDistribution`.","properties":{"topics":{"type":"array","maxItems":8,"items":{"type":"string","maxLength":120},"description":"More topics or dimensions to research, e.g. \"media use\" or \"income\"."}}}}},"examples":{"adjust":{"value":{"instruction":"Make it 60% women and skew younger"}},"addDistribution":{"value":{"requestedDistribution":"Preferred furniture materials"}},"grow":{"value":{"instruction":"And now add 10 consumers from Nigeria"}},"selection":{"value":{"distributions":[{"name":"Gender","distribution":[{"label":"Female","pct":60,"sourceIdx":0},{"label":"Male","pct":40,"sourceIdx":0}]}]}}}}}}}},"/api/v1/audiences/{audienceId}/recalibrations/{operationId}":{"get":{"responses":{"200":{"description":"Current operation status, result and safe terminal error."},"401":{"description":"Authentication required."},"404":{"description":"Audience or operation not owned by the caller."}},"operationId":"getAudienceRecalibration","summary":"Read a durable Audience recalibration result","description":"Owner, or the confirmed staff actor while its original support authorization remains valid: existing direct Audience admin collaboration or the exact active customer-issued support grant. Poll the receipt returned by recalibrateAudience. A completed receipt retains the grounding and member counts; a failed receipt retains its refusal or safe error. Support actors use get_audience_creation_progress with audienceId and recalibrationId; this permission does not grant general Audience or workspace reads.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"operationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/regenerate-images":{"post":{"responses":{"200":{"description":"Summary of what was queued.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["audienceId","totalMembers","candidates","enqueued","skipped","errors","dry","sample"],"properties":{"audienceId":{"type":"string","format":"uuid"},"totalMembers":{"type":"integer","minimum":0},"candidates":{"type":"integer","minimum":0,"description":"Members matching the filter (missing portrait, or all when `force`), after `limit`."},"enqueued":{"type":"integer","minimum":0,"description":"Jobs actually queued; 0 on a dry run."},"skipped":{"type":"integer","minimum":0,"description":"Members left alone because they already have a portrait or belong to another user."},"errors":{"type":"integer","minimum":0,"description":"Members whose job could not be queued."},"dry":{"type":"boolean"},"sample":{"type":"array","maxItems":10,"description":"The first up to 10 queued (or, on a dry run, candidate) Minds.","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}}}}}}}}}},"400":{"description":"`Audience ID is required` or `Invalid audience ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Audience not found`: the Audience does not exist or the caller is not its owner."}},"operationId":"regenerateAudienceImages","summary":"Queue profile-image generation for the Minds in an Audience","description":"Bulk-enqueues portrait generation for the member Minds owned by the caller. Audience owner only; Minds owned by other users are skipped. By default only members without a `profileImageUrl` are queued; `force: true` replaces existing portraits after successful generation. Fire-and-forget: the response returns as soon as the jobs are queued, and images arrive asynchronously; poll `GET /audiences/{audienceId}` (member `profileImageUrl`) or `GET /minds/{mindId}`. Use `dry: true` to see what would be queued without queuing anything.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"description":"Audience ID (UUID).","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","default":false,"description":"Regenerate even for Minds that already have a portrait (the current portrait stays visible until its replacement is ready)."},"limit":{"type":"integer","minimum":1,"description":"Cap the number of Minds queued in this call (oldest members first). No cap by default."},"dry":{"type":"boolean","default":false,"description":"Report the candidates without enqueueing."}}},"examples":{"missingOnly":{"value":{}},"forceFirstTen":{"value":{"force":true,"limit":10}}}}}}}},"/api/v1/audiences/{audienceId}/support/{grantId}":{"delete":{"responses":{"200":{"description":"Revoked support grant in data."},"404":{"description":"Audience or grant not found for this owner."}},"operationId":"revokeAudienceSupport","summary":"Revoke Audience support access","description":"Current owner only; idempotent. Stops new admission and queued/resumed work at authorization checkpoints. An already running atomic step may finish; completed changes are not undone. Returns the retained grant including revokedAt.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"grantId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/support/activity":{"get":{"responses":{"200":{"description":"data.operations and data.nextCursor."}},"operationId":"listAudienceSupportActivity","summary":"Read Audience support activity","description":"Owner-visible retained actor, reason, requested change and operation status. Authorized staff see only their current grant activity. Ten operations per page; pass nextCursor as cursor. Read the statusUrl for the full retained result or terminal refusal.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/support":{"get":{"responses":{"200":{"description":"data.grants and data.nextCursor."}},"operationId":"listAudienceSupport","summary":"List Audience support grants","description":"Owner sees grant and revocation history. An authorized staff member sees only their current grant. Returns up to 50 grants and nextCursor; pass cursor to continue.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"cursor","in":"query","schema":{"type":"string","format":"uuid"}}]},"post":{"responses":{"200":{"description":"Support grant in data; creation is recorded without sending email."},"400":{"description":"Invalid staff identity or expiry."},"404":{"description":"Audience unavailable to this owner."},"409":{"description":"Request key conflict."}},"operationId":"grantAudienceSupport","summary":"Grant expiring Audience support access","tags":["Audiences"],"description":"Current owner only. Grants a confirmed, active getminds.ai staff account permission to amend this Audience composition and read its support receipts. No workspace membership, ownership transfer, member growth, shared-Mind waiver or billing allowance change. Maximum 30 days. Renewing revokes older grants to the same staff member; old jobs cannot inherit the renewal. Reuse requestKey with identical input to replay the grant; conflicting input returns 409.","security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"audienceId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["requestKey","staffEmail","reason","expiresAt"],"properties":{"requestKey":{"type":"string","format":"uuid"},"staffEmail":{"type":"string","format":"email","maxLength":320},"reason":{"type":"string","minLength":1,"maxLength":1000},"expiresAt":{"type":"string","format":"date-time"}}}}}}}},"/api/v1/audiences/{audienceId}/validations/{validationId}":{"get":{"responses":{"200":{"description":"Validation.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Audience or validation not found."}},"operationId":"getAudienceValidation","summary":"Get an Audience validation with scores (experimental)","description":"Experimental. Returns stored validation scores. Older results without question ranges derive them once from the original saved answers and store them; saved scores are not changed. `scores.headline` is macro MAE in percentage points with a 95% band (clustered bootstrap over Minds and survey sampling, widened by any re-weighting to the Audience's composition) and the noise floor (the MAE sampling alone would produce). `scores.kpis` lists every KPI of the experiments methodology catalog, each with its value, a 95% interval and the number of questions it covers: MAE, RMSE, total variation distance, Jensen-Shannon divergence and distance, ordinal Wasserstein distance, expected set-size error, top-choice agreement, Pearson and Spearman correlation within questions and pooled across options, and the expected Brier and log scores. `scores.validity` counts invalid answers by reason (unknown option, too many selections, an exclusive option combined with others, empty); they stay in the denominator. Each question lists human and synthetic shares per option and its own 95% match-score range, using the same sampling and measured population-shift method as the headline. When a scored question has no stated respondent count (`baseSource: assumed`), its point comparison and existing weight are retained, but its range and noise floor are null. Headline and combined ranges, band bounds and level, and affected KPI intervals are also null when their contributors include such a question. This applies to saved results as well as new scores; a legacy placeholder n is never treated as observed sample size.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"validationId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/validations/batches/{batchId}/cancel":{"post":{"responses":{"200":{"description":"The batch, stopping or already ended.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Audience or batch not found."},"409":{"description":"The surveys are already being asked."}},"operationId":"cancelAudienceValidationBatch","summary":"Stop a validation before its surveys are asked","description":"Stops a batch while `canCancel` is true: it is still queued or its surveys are still being read. Nothing has been asked of the Minds yet, so no synthetic responses have been used. Once the surveys are being asked the answers are already being generated and the batch can no longer be stopped (409). Stopping a batch that already ended returns it unchanged.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"batchId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/validations/batches/{batchId}":{"get":{"responses":{"200":{"description":"The batch.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Audience or batch not found."}},"operationId":"getAudienceValidationBatch","summary":"Get one validation of an Audience, with its progress and results","description":"`provenance` records what produced the validation, for explaining and reproducing a result: the build commit, the scoring method, how many questions were judged, kept and left out and why, engine and extraction-contract versions, every validation prompt by content hash with the provider and model it resolved to, the version of the Audience that was asked (ready Minds, grounding snapshot id, hash and revision), what was requested, the limits in force, every chosen study with its relation, fit tier and the questions available and asked, the web search (id, queries, counts), and, once the runs settle, per study the models that answered by stage, token usage, execution, estimation and surface-treatment versions, and answer coverage. `outcome.fitted` is set when the chosen studies were trimmed to the responses left. The batch a `POST /audiences/{audienceId}/validations` returned. `status`: `queued` and `preparing` (the surveys are being read and compared with the Audience), `running` (`progress.questionsAnswered` of `progress.questionsTotal`), then `completed`, `failed` (`failure.code` and `failure.reason`; `NOT_ENOUGH_RESPONSES` means the whole validation did not fit the synthetic responses left, `NOT_ENOUGH_QUESTIONS` that fewer than 8 questions fit this Audience; in both nothing was spent) or `cancelled`. `outcome.questionSelection` says how many questions the chosen studies held (`questionsJudged`), how many the judge ruled a fair target for this Audience (`questionsKept`), how many were actually asked once the studies kept, the wider-population cap, the question budget and the responses left had taken their cut (`questionsAsked`; `questionsKept` minus it is what a budget dropped rather than the judge), and every question left out by the judge with its reason: `not_applicable` (the Audience's people cannot answer it), `answer_differs` (its published answers are no fair target for this Audience), `asked_in_another_study`, `off_topic` (from a survey of other or broader people and not about what defines this Audience, or fewer than half that survey's usable questions were) or `no_eligible_minds` (its shares are of people who do something, such as play a sport, and fewer than 10 Minds evidence doing it; with enough, it is asked only of them as its own survey, named `(asked of …)`). `outcome.groundingHoldout` lists questions not asked because they are distributions the Audience was built from. `surveys` are the ones asked, each with `score` and `range` once scored and `people`, how far the Audience could be checked against the survey's respondents (`same`, `similar`, `unknown` when the survey publishes nothing about them, `related` when it asked a broader audience). `outcome.surveysDiscarded` names every survey that was found for this Audience and then not asked, with the reason: `different_people` (the people it asked tell nothing about these people), `population_mismatch` (its published composition and the Audience do not overlap) `ranked_lower` (it fits, but better-fitting studies filled the validation) or `grounding_source` (it is one of the sources the Audience was built from, by URL, DOI, title or survey identity, so it cannot test it). `notComparable` names the surveys that described different people, with the reason, including the ones discarded before they were read. Each asked survey carries `fieldPeriod`, the source-authored fieldwork or publication period when verified, otherwise null, and `caveats`: what its number does not mean, including shares of organisations rather than people, unverified reporting units (`relation.reportedPer: unknown`), and unverified residence. `relation.reviewStatus: needs_review` marks an unjudged population relation. Organisation-weighted results are evidence about these people but are not a like-for-like target. `combined` weighs the scored surveys by the questions each scored and by who it asked — a survey of the Audience's own people counts in full (historical unscoped part-population checks retain their original weight), a neighbouring audience at a half and the wider population they belong to at a quarter — and carries `basis`, whose answers it compares the Audience with: `kind: audience` when at least 8 of the questions asked came from surveys of these people (or a part of them); `kind: wider_population` when fewer but at least one did and, together with surveys of the wider population they belong to (or of the same kind of people elsewhere), at least 8 were asked — then the score is a lower-confidence (`confidence: lower`) comparison with that population, never with the Audience's own people, `audienceQuestions` says how many questions about these people it holds (0: no survey of them was found) and `comparedWith` names who the wider-population surveys asked. `combined` is absent when neither holds, such as a check resting on neighbouring audiences; a survey scored on fewer than 3 questions states no score of its own and carries no weight. `outcome.evidenceBasis` records a validation assembled as a wider-population comparison. A validation with no question about these people or a part of them states no `combined` score: `outcome.contextOnly` marks it, and its survey results are context about the wider population. `NOT_ENOUGH_SPECIFIC_EVIDENCE` means fewer than 8 of the questions found came from surveys of these people or of the wider population (the rest from neighbouring audiences; `details` counts each), and nothing was spent. Poll no faster than every five seconds. Reading never starts or scores anything. Surveys tested on a subset carry `respondentScope`: population, selected and total Audience members, confirmed/supported matches, unknowns and excluded members. Their match percentages describe only that subset; they contribute to `combined` or `overall` only on a `subgroups` basis (too few questions were put to the whole Audience, so surveys of parts of it, each answered only by the matching Minds, carry the score), and each survey's `inCombined` says whether the combined score rests on it.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"batchId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/audiences/{audienceId}/validations/file-check":{"post":{"responses":{"200":{"description":"`{ status: reading }`, `{ status: done, failure, questionsFound, questionsScored }`, or null.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","nullable":true,"additionalProperties":true}}}}}},"400":{"description":"Invalid request."},"401":{"description":"Unauthorized."},"404":{"description":"Audience not found or not editable by the caller."}},"operationId":"checkAudienceValidationFiles","summary":"Check survey files before validating an Audience against them","description":"Reads the survey files the way a validation reads them, together as one survey, and says whether they hold questions and published results to compare against, before any validation starts. The first call starts the reading and answers `reading`; repeat the same call until `done` (the reading takes seconds for a short file and a few minutes for a long deck). `failure.code` is `SURVEY_RESULTS_NOT_FOUND` for a questionnaire without results, `SURVEY_NOT_FOUND` when no survey questions were found, or `SURVEY_FILES_UNREADABLE`; null when the files can be validated against. A validation started with the same files reuses the reading. `data` is null when files cannot be checked ahead; the validation then reads them itself. Nothing is spent.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["files"],"properties":{"files":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string"},"url":{"type":"string"}}}},"population":{"type":"string","description":"Which reported audience of respondents to read, as for a validation with `files`."}}}}}}}},"/api/v1/audiences/{audienceId}/validations":{"get":{"responses":{"200":{"description":"Validations and the Audience-level summary.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"summary":{"type":"object","additionalProperties":true},"audiences":{"type":"array","items":{"type":"object","additionalProperties":true}},"batches":{"type":"array","items":{"type":"object","additionalProperties":true}},"overall":{"type":"object","nullable":true,"additionalProperties":true},"included":{"type":"object","nullable":true,"additionalProperties":true},"responses":{"type":"object","nullable":true,"additionalProperties":true},"minds":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Audience not found or not editable by the caller."}},"operationId":"listAudienceValidations","summary":"List an Audience's survey validations","description":"Everything this Audience has been checked against. `batches` lists each validation request, newest first, with its status, progress while it runs, its scored surveys (`score` = 100 − MAE with a 95% `range`, and `people`: how far the Audience's composition could be checked against the survey's respondents) and the combined result across its surveys. `overall` is how close the Audience is to real surveys across all of them: each survey counts once, by its latest scored check, weighted by questions scored. `combined` and `overall` carry `basis`: `kind: audience` when the score rests on surveys of the Audience's own people, or `kind: wider_population` with `confidence: lower` when no check held enough of them and the score is a comparison with the wider population they belong to (`comparedWith` names who those surveys asked; `audienceQuestions` 0 means no survey of these people was found). The two are never mixed: while any check of the Audience's own people exists, `overall` rests on those checks alone. `included` is the plan's validations that cost no responses this month (`plan` identifies the tier; `perMonth` −1 = unlimited, 0 = none included; further validations are billed in responses). `responses` is the synthetic responses the caller has left this month, which validations beyond the included ones are billed from like any Study (`remaining` −1 = unlimited; null when the plan could not be read). `minds` is how many of the Audience's Minds are ready and the `minimum` a validation needs; below it a validation is refused with `AUDIENCE_TOO_SMALL`. Each survey of a batch carries `relation`: who it asked relative to the people who define the Audience (`same`, `part`, `neighbouring`, or `wider` for the broad population they belong to), and surveys are listed in that order. It also carries `fieldPeriod`, when the survey was in the field as its source states it, or null where the source states no date. `outcome.search` on an automatic validation says how many sources the web search read, how many surveys it found, and what each source came to. `data` lists the individual validations without per-question detail, and `summary.verdict` is the latest settled one: `validated`, `approximate`, `not_comparable`, or `not_validated`. `identity` on batches and `overallIdentity` report whether survey identity was verified. With `needs_review`, individual results remain visible, combined/overall scores and distinct-survey counts are null, and `reason` identifies the unresolved reading. Reading never starts or scores anything. Surveys tested on a subset carry `respondentScope`: population, selected and total Audience members, confirmed/supported matches, unknowns and excluded members. Their match percentages describe only that subset; they contribute to `combined` or `overall` only on a `subgroups` basis (too few questions were put to the whole Audience, so surveys of parts of it, each answered only by the matching Minds, carry the score), and each survey's `inCombined` says whether the combined score rests on it.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}}]},"post":{"responses":{"202":{"description":"Validation accepted and queued. `data` is the batch; `included` is what the plan includes and whether this run is one of them; `responses` is the synthetic responses left this month (`remaining` −1 = unlimited).","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":true},"included":{"type":"object","additionalProperties":true},"responses":{"type":"object","nullable":true,"additionalProperties":true}}}}}},"400":{"description":"Invalid request, unknown benchmarkId, or an unreadable dataset."},"401":{"description":"Unauthorized."},"403":{"description":"No included validation is left and the synthetic responses left cannot pay for the smallest run (8 questions for every ready Mind): the standard plan-limit error, before anything is queued; or a respondent dataset on a plan other than Team; or the Audience exceeds the plan size limit (`limitType: audienceMembers`). Nothing is queued or spent."},"404":{"description":"Audience not found or not editable by the caller."},"409":{"description":"The request key was already used for a different Audience."},"413":{"description":"Dataset exceeds the review limit."},"422":{"description":"`AUDIENCE_TOO_SMALL`: the Audience has fewer ready Minds than a validation needs (`data.minds`, `data.minimum`). `SPREADSHEET_EVIDENCE_UNRESOLVED`: a spreadsheet role could not be verified; retry the reading or review the table structure. Nothing is queued or spent."},"503":{"description":"The subscription could not be verified; retry."}},"operationId":"createAudienceValidation","summary":"Validate an Audience against real surveys","description":"Checks the Audience against a real survey (the benchmark) and returns at once: the work runs in the background and the response is the validation batch to poll. Give the survey in one of these ways: a listed survey (`benchmarkId`: `study:<id>`, a public survey the evidence pool holds, `discovered:<id>` found by a web search, or `saved:<validationId>`, a survey you supplied in an earlier validation; `GET /audiences/validation-benchmarks?audienceId=` ranks them), one or more listed surveys (`benchmarkIds`, 1 to 5: asked together in one run, with results per survey), a respondent-level dataset (`dataset`: a spreadsheet already attached to the Audience via `sourceId`, or any uploaded XLS/XLSX/CSV/SPSS-SAV `file`; Pro plan), survey files (`files`: questionnaire and results in PDF, XLS/XLSX/CSV/SPSS-SAV, DOC/DOCX, TXT, PowerPoint or ZIP; questions and response formats are read as custom Study mode reads an uploaded questionnaire, and published shares are kept only when a verbatim passage of the files, or a chart read from a PDF page layout or native PowerPoint chart, supports each one; a single respondent-level spreadsheet is treated as a `dataset`), or aggregated results you supply (`benchmark`). Listed surveys may be combined with `files`, which count as one additional survey toward the limit of five. To review public surveys before starting, search and list the benchmarks first, then send the selected `benchmarkIds`; no further surveys are discovered or substituted. Plans include validations that cost no synthetic responses, set per plan in billing: by default five runs per seat each billing month on Pro (pooled across the team), two on Starter, one on Free, and a contract number on Enterprise; earlier subscriptions keep the number their price was sold with. One run is one request, whether it asks one study or five, and a run that ends without a score or any included answers spent gives its slot back (`included` reports `plan`, `perMonth` −1 for unlimited, `used`, `remaining`, `renewsAt`, and `thisRun`). Scoring an existing run never takes an included validation and costs nothing. When no included validation is left a validation still starts and is billed like any Study, one synthetic response per Mind per question (`responses` shows what is left): studies chosen for you are fitted to the responses left, best fit first (`outcome.fitted`); when the responses left cannot pay for 8 questions for every ready Mind the request is refused with the standard responses plan-limit error before anything is read or queued, and a batch that runs short later ends `failed` with `NOT_ENOUGH_RESPONSES` with nothing spent. Studies chosen for you are checked question by question before anything is asked: a question is left out when the Audience's people cannot answer it, when its published answers are no fair target for this Audience (who answered differs in a way that changes the answer; a question published by age or region is narrowed to the Audience's own mix first), or when a better-fitting study asks it already (`outcome.questionSelection`, every question left out with its reason). A validation needs at least 8 such questions after every step; below that it ends `failed` with `NOT_ENOUGH_QUESTIONS` and nothing is spent (surveys you upload are asked as given). New private Audiences are validated automatically, once, as soon as their Minds are fully trained (every member `fullyTrained` on `GET /audiences/{audienceId}/progress`: done learning from its sources, a few minutes after the Audience is ready to chat), while included validations are left; Audiences created before automatic validation shipped are validated only on request. All surveys of a validation run in one Study (`Validation run: <Audience>`) that stays out of Study lists and limits. A validation someone started that ran longer than a few minutes emails that person when it finishes, with a link to the Audience's Validation tab. A validation needs at least 10 ready Minds. One validation asks at most 60 questions per survey and 30,000 answers in total. Poll `GET /audiences/{audienceId}/validations/batches/{batchId}` until `status` is `completed`, `failed` or `cancelled`: `queued` and `preparing` mean the surveys are being read and compared with the Audience's composition (a survey describing different people is reported under `notComparable` and nothing runs for it), `running` carries `progress`. `POST .../batches/{batchId}/cancel` stops a batch while `canCancel` is true, before any of its surveys is asked. Each scored survey carries `score` (100 − MAE) and its 95% `range`; `GET /audiences/{audienceId}/validations/{validationId}` has every KPI and question. To score a run that already exists, pass `run: { studyId, runId }`. Send `requestKey` (or an `Idempotency-Key` header) to make a retried request return the same batch.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"benchmarkId":{"type":"string","description":"A survey id from GET /audiences/validation-benchmarks."},"benchmarkIds":{"type":"array","minItems":1,"maxItems":5,"uniqueItems":true,"items":{"type":"string"},"description":"Validate against exactly these reviewed surveys. May be combined with files; uploaded files count as one additional survey toward the limit of five. The selected surveys are asked together in one run. No additional surveys are discovered or substituted."},"findSurveys":{"type":"boolean","description":"Let the best-fitting surveys be chosen instead of naming one. `true` searches for published surveys whose respondents are the people who define this Audience (a web search from the last day is reused), then of a neighbouring audience, then of the wider population they belong to, keeps only the questions whose published answers fit this Audience (`outcome.questionSelection`), and asks up to 60 of them in that order from as many studies as hold them (at most twelve, reading up to twice as many ranked studies so a study emptied by that check is replaced by the next-best one): every study keeps a share and the best-fitting are filled first (`outcome.questionsCapped`), after any `files` you upload; the modules of one study count as one survey, each survey carries `relation`, and `outcome.search` lists every source read with what it came to; `false` with `files` validates against your files only. Cannot be combined with the other ways of giving a survey. `outcome.phase` on the batch says whether it is `reading` your files or `finding` surveys."},"population":{"type":"string","description":"Which population the uploaded files report to validate against, as they name it (\"Detroit\"). Defaults to the one with the most questions (usually the whole sample); `fileExtraction.populations` lists the others."},"files":{"type":"array","maxItems":20,"description":"Survey files uploaded with the request (workspace upload or public URLs). `fileExtraction` in the response lists the questions found, the ones scored, and why others were left out.","items":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string"},"url":{"type":"string"}}}},"dataset":{"type":"object","description":"Respondent-level survey data. Pass `sourceId` (a spreadsheet source of this Audience) or `file`. Coded headers such as \"Q5\" need respondent-visible wording in `questionText` (keyed by the variable key returned in `datasetExclusions`). Columns that describe who answered (screener and population variables) become the population composition and are scored only when `variables` names them.","properties":{"sourceId":{"type":"string","format":"uuid"},"file":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string"},"url":{"type":"string"}}},"name":{"type":"string","description":"Display name for the benchmark."},"population":{"type":"string","maxLength":2000,"description":"Who was surveyed, as respondents would recognise it (\"Owners of small businesses in Germany\"). Each Mind is checked against it before answering. Defaults to the respondent count and the composition of the columns that describe who answered."},"questionText":{"type":"object","additionalProperties":{"type":"string"}},"variables":{"type":"array","items":{"type":"string"},"description":"Only replay these variables (population variables included when named)."}}},"benchmark":{"type":"object","additionalProperties":true,"description":"Your own survey: { name, source?, population: { description, sampleSize, composition?: [{ name, dimension?, segments: [{ label, share }] }] }, questions: [{ id, text, module?, response, ordinal?, targets: [{ option, share }], n?, bySegment? }] }. Shares are fractions; single-choice targets sum to 1, multiselect targets are per-option selection rates."},"run":{"type":"object","required":["studyId","runId"],"properties":{"studyId":{"type":"string","format":"uuid"},"runId":{"type":"string","format":"uuid"}},"description":"Score an existing research run of this Audience instead of preparing a new one."},"confirmation":{"type":"object","required":["accepted"],"properties":{"accepted":{"type":"boolean","enum":[true]}},"deprecated":true,"description":"No longer needed: a validation always starts."},"requestKey":{"type":"string","minLength":8,"maxLength":200,"description":"Your key for this request. Repeating it returns the batch the first request created instead of starting another."}}}}}}}},"/api/v1/audiences/active-progress":{"get":{"responses":{"200":{"description":"Active Audience progress snapshots."},"401":{"description":"Unauthorized."}},"operationId":"listActiveAudienceProgress","summary":"List active Audience creation progress","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/audiences/allocation-preview":{"post":{"responses":{"200":{"description":"Deterministic allocation preview."},"400":{"description":"Invalid count or distributions."},"401":{"description":"Missing or invalid API key."}},"operationId":"previewCohortAllocation","summary":"Preview deterministic cohort allocation","description":"Convert marginal distributions into exact integer quotas and deterministic member profiles without creating an Audience. This is the contract intended for API clients and future product UI controls.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["memberCount"],"properties":{"memberCount":{"type":"integer","minimum":1,"maximum":1000},"seedBasis":{"type":"string","maxLength":1000},"distributions":{"type":"array","maxItems":200,"items":{"$ref":"#/components/schemas/GroundingDistribution"}},"cohortAllocation":{"type":"object"},"reviewedGroundingJson":{"type":"string","description":"Unchanged reviewed snapshot. Its rules and axis metadata are retained."},"reviewedGroundingSha256":{"type":"string"},"researchStudyAnalysis":{"type":"object","description":"Questionnaire analysis including routing rules, when sending distributions directly."}}}}}},"parameters":[]}},"/api/v1/audiences/from-brief":{"post":{"responses":{"200":{"description":"Either an idempotent replay (the supplied idempotency key already created an audience within the replay window; returns that audience with `replayed: true`, nothing new is created, no plan allowances are consumed, `datasetSegmentation` is not reconstructed) or a saved-snapshot/internal `groundingPreview` result containing reviewed grounding, checksum, effective cohortAllocation audit, flags, and size with no Audience or Minds created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/AudienceFromBriefResult"}}}}}},"201":{"description":"Grounded audience created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/AudienceFromBriefResult"}}}}}},"202":{"description":"Creation or a fresh public grounding preview accepted by the processor, including when async is omitted or false. Saved-snapshot previews also return 202 when explicitly requested asynchronously. Poll `data.statusUrl` until completed or failed; `data.result` contains the same completed response as a synchronous request.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["jobId","status","progress","statusUrl"],"properties":{"jobId":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","processing","completed"]},"progress":{"type":"integer","minimum":0,"maximum":100},"statusUrl":{"type":"string"}}}}}}}},"400":{"description":"Missing `text`, text too long, or invalid input."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Plan limit reached (`code: PLAN_LIMIT`): a stated count above the per-Audience allowance. A count within the allowance is never refused: above the 20-Mind Balanced ceiling it moves to a deeper creation mode when the plan includes one, and otherwise is built at that ceiling with a note in the allocation warnings."},"409":{"description":"An idempotency key is already in progress or was reused with a different explicit member count, or the reviewed grounding checksum does not match."},"422":{"description":"No personas could be derived from the brief; required composition targets cannot be mapped (`code: AUDIENCE_REQUIREMENTS_UNMAPPED`); or (`code: AUDIENCE_SOURCE_FILE_ACCESS_DENIED` / `AUDIENCE_SOURCE_FILE_UNAVAILABLE`, `files`) a supplied file could not be opened from this account or fetched. Review the input; no Audience was created."},"500":{"description":"Internal server error."},"503":{"description":"A service the build depends on is temporarily unavailable. Retry the same operation with its original idempotency key. Durable builds retain private recovery progress. An unavailable consistency reader is not a 503: members it could not read are written from their facts and read again when their Minds are trained. A draft edit whose reading did not come back within its hold returns `AUDIENCE_EDIT_UNREAD`: nothing changed; send the same edit again."}},"operationId":"createAudienceFromBrief","summary":"Create a grounded audience from a brief","description":"Create one Audience from a free-text brief. Attached research files use the same extended screener/questionnaire analysis as the in-app New Audience flow, including Study roles, screening and quota rules, review distributions, and grounding provenance. Public bearer-authenticated V1 requests return `202 Accepted`; poll the returned status URL until the durable processor operation completes.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string"},"description":"Retry-safety key, max 200 chars (also accepted as the `idempotencyKey` body field; the header wins). Creation can exceed typical client timeouts — retrying with the same key within 6 hours returns the audience the original request created (200, `replayed: true`) instead of creating a duplicate."},{"name":"Prefer","in":"header","required":false,"schema":{"type":"string","enum":["respond-async"]},"description":"Return 202 after durable admission and run the complete build on the processor."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":200000,"description":"Free-text brief describing the audience or population to represent."},"name":{"type":"string","description":"Optional audience name override. When omitted, the server names the audience from the brief or detected personas."},"files":{"type":"array","description":"Already-uploaded research files analyzed through the same extended Audience study-ingestion path as the in-app New Audience uploader.","items":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string"},"url":{"type":"string"}}}},"links":{"type":"array","description":"URLs to scrape for additional context.","items":{"type":"string"}},"keywords":{"type":"array","description":"Search keywords used as extra context and research seeds.","items":{"type":"string"}},"includeWebSearch":{"type":"boolean","default":true,"description":"When false, skips Exa search/extraction completely and grounds only on the supplied brief, files, links, keywords, and structurally parsed respondent data. A study report, questionnaire, screener or respondent dataset still grounds the Audience but is withheld from the members' own knowledge (see `withheldFromMemberKnowledge`), so it is not evidence they can answer from; when nothing survives that filter the request is refused with 400 rather than creating Minds with no evidence."},"isLinkSharingEnabled":{"type":"boolean","description":"Enable public link sharing for the created audience."},"generateImages":{"type":"boolean","default":true,"description":"Generate AI profile images and an audience cover asynchronously for members the approved persona-image catalog could not serve. Catalog portraits are assigned either way — that is asset selection, not generation — so `false` avoids every image-model call for this creation while members still receive real portraits wherever the catalog matches; only unmatched members keep the initials fallback."},"trainMembers":{"type":"boolean","default":true,"deprecated":true,"description":"Deprecated; omit it. Every member of every Audience is individually trained in the background, including large reviewed-dataset cohorts (> 40 Minds), through the same per-member pipeline the in-app flow uses, keeping each Mind's deterministic cohort profile and the request locale. `true` is accepted as a no-op; `false` is rejected with 400 `TRAIN_MEMBERS_OPT_OUT_REMOVED` (it used to create untrained Minds with an empty system prompt that reported ready). Cost and time: each member consumes one Mind training (research, knowledge and prompt generation); a 100-Mind cohort typically finishes over tens of minutes to a few hours, staggered per Audience. The response returns as soon as the Audience exists; poll GET /api/v1/minds/{mindId}/training per member (or the Audience progress endpoint) and wait for every member to report readyToChat before running a Study — Study runs refuse Audiences with untrained members."},"idempotencyKey":{"type":"string","maxLength":200,"description":"Retry-safety key (same semantics as the `Idempotency-Key` header, which wins when both are sent). Reusing the key within 6 hours replays the audience it created instead of duplicating it."},"async":{"type":"boolean","description":"Optional async hint for internal cookie-authenticated callers. Public bearer-authenticated V1 requests are always enqueued and return a pollable 202 operation."},"draftPreview":{"type":"boolean","description":"Generate the same durable draft as the webapp: streamed research, distributions, and proposed Minds. Always returns a 202 operation; its completed result contains draft.id and draft.sha256. No Audience or Minds are materialized until acceptance."},"reviewedDraftId":{"type":"string","format":"uuid","description":"Owned draft.id returned by the native draft preview. Pass with reviewedDraftSha256 to rework or accept that roster."},"reviewedDraftSha256":{"type":"string","pattern":"^[a-fA-F0-9]{64}$","description":"Exact draft checksum from the latest review. Stale reviews fail before materialization."},"draftRework":{"type":"string","maxLength":200000,"description":"Refinement instruction, with draftPreview:true and the reviewed draft pair. The original brief and earlier revisions remain in context. When the instruction cannot be placed on one of the draft's charts, the draft is returned unchanged with `clarification`: a question to ask the user before reworking again."},"groundingPreview":{"type":"boolean","default":false,"description":"Review the quota axes before any Mind exists. When true the request runs research grounding plus a deterministic allocation preview and returns the reviewed grounding, checksum, effective cohortAllocation audit, flags, and size without creating an Audience or Minds or consuming generation allowance. Fresh public previews always return a durable 202 operation, including when `async` is omitted or false. Saved-snapshot previews may return inline; send `async: true` or `Prefer: respond-async` to queue those too. Poll its status URL for the same preview result. Explicit allocation targets that cannot match the grounded axes are set aside and listed in `cohortAllocation.audit.warnings` (or as a `target_unapplied` notice on the grounding), never refused, just like creation. If research did not finish, the preview says so (`research_unavailable`) and creating from it researches the Audience in the background. Axes that measure the Study outcome itself are demoted to supplementary context and listed in `flaggedDistributions`."},"reviewedGroundingJson":{"type":"string","maxLength":2000000,"description":"Exact reviewed grounding snapshot returned by a prior preview. Send it unchanged with reviewedGroundingSha256 to re-preview revised exclusions/allocation options against the same evidence, or to create from the latest accepted preview without rerunning grounding research."},"reviewedGroundingSha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$","description":"SHA-256 returned with reviewedGroundingJson. Both fields are required together; creation fails before materialisation when the checksum does not match."},"excludeDistributions":{"type":"array","maxItems":200,"items":{"type":"string"},"description":"Exact axis names whose composition quotas should be removed. Age remains as one eligibility range without within-range shares; explicit gender membership remains enforced. Include required eligibility axes in cohortAllocation.distributionNames. Original evidence stays in reviewDistributions."},"memberCount":{"type":"integer","minimum":1,"maximum":1000,"description":"Exact number of Minds to create. Wins over any count parsed from `text` and over grounding suggestions, while remaining subject to the effective plan and creation-mode caps."},"audienceCreationMode":{"type":"string","enum":["balanced","segment_coverage","benchmark_depth"],"deprecated":true,"description":"Deprecated alias for `audienceCreationMode`. If both fields are supplied, their values must match."},"datasetSegmentation":{"type":"object","description":"Reviewed research-variable roles, distributions, privacy-safe pairwise relationships, and deterministic dependencies (recodes and questionnaire routing filters) returned by the segmentation-preview endpoint. Pass `functionalDependencies` and `dependencyDiscovery` through unchanged: the first are hard constraints, so a synthetic respondent never breaks a recode and a filtered question stays unanswered at the source rate; the second reports which discovery bounds applied and is echoed into `cohortAllocation.audit.jointConsistency`. Omitting it does not disable enforcement, but the audit will say the bounds are unknown. Requires Team plus `benchmark_depth`. Structural variables shape a representative cohort; outcomes remain held out and observed joint combinations remain audit evidence rather than respondent-like Minds."},"cohortAllocation":{"type":"object","description":"Deterministic allocation controls. Grounded marginals are converted into exact integer quotas server-side; the LLM does not decide proportions. Omit for deterministic defaults.","properties":{"enabled":{"type":"boolean","default":true},"seed":{"type":"string","maxLength":200},"distributionNames":{"type":"array","maxItems":500,"items":{"type":"string"}},"maxDistributions":{"type":"integer","minimum":1,"maximum":500,"default":500},"minSegmentCount":{"type":"integer","minimum":0,"maximum":20,"default":0},"targetOverrides":{"type":"array","maxItems":500,"description":"Partial or full target-percentage overrides. Unspecified segments keep their source percentages; the audit preserves sourcePct and normalizedTargetPct separately.","items":{"type":"object","required":["distribution","segments"],"properties":{"distribution":{"type":"string"},"segments":{"type":"array","items":{"type":"object","required":["label","pct"],"properties":{"label":{"type":"string"},"pct":{"type":"number","minimum":0,"maximum":100}}}}}}},"jointStrategy":{"type":"string","enum":["independent","aligned","observed"],"default":"independent"},"includeProfilesInResponse":{"type":"boolean","default":false}}}}},"examples":{"demographicAudience":{"summary":"Create an Audience","value":{"text":"Berlin Spati customers who buy late-night snacks","name":"Berlin Spati Customers","links":["https://example.com/customer-research"],"keywords":["Berlin convenience store demographics"]}}}}}}}},"/api/v1/audiences/from-brief/jobs/{jobId}":{"get":{"responses":{"200":{"description":"Current operation state and, when terminal, its result or error."},"401":{"description":"Missing or invalid API key."},"404":{"description":"Operation not found or not owned by the caller."}},"operationId":"getAudienceFromBriefCreationJob","summary":"Get a from-brief Audience preview or creation operation","description":"Poll the durable operation returned by an asynchronous from-brief preview or creation request. A running operation reports `progress` (0-100) and its `stage` (`phase`: researching, drafting, building or training, plus the research `step` while researching); research usually takes several minutes. A completed preview returns its reviewed grounding and checksum without creating an Audience or Minds.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/v1/audiences/from-brief/jobs/{jobId}/progress":{"get":{"responses":{"200":{"description":"Creation snapshot and a five-minute read-only stream grant."},"401":{"description":"Unauthorized."},"404":{"description":"Operation not found."}},"operationId":"getAudienceCreationProgress","summary":"Read Audience creation progress and open a scoped live subscription","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}},{"in":"query","name":"portraits","required":false,"schema":{"type":"string","enum":["inline"]},"description":"inline adds `portraits`: a small data: thumbnail per signed portrait URL, for embedded views whose host blocks image origins."}]}},"/api/v1/audiences/from-brief/segmentation-preview":{"post":{"responses":{"200":{"description":"Complete variable distribution review."},"400":{"description":"Malformed JSON, invalid preview input, or unsupported, empty, or invalid spreadsheet."},"401":{"description":"Missing or invalid authentication."},"403":{"description":"Pro plan required or upload access denied."},"413":{"description":"JSON request exceeds 256 KiB or dataset exceeds the explicit review limit; no partial preview is returned."},"422":{"description":"SPREADSHEET_EVIDENCE_UNRESOLVED or DATASET_INTERPRETATION_UNRESOLVED: respondent structure, column meaning or coding could not be verified. Retry the reading or clarify the source."},"500":{"description":"Internal server error. All responses are private and non-cacheable."},"503":{"description":"Entitlement lookup temporarily unavailable."}},"operationId":"previewAudienceDatasetSegmentation","summary":"Preview spreadsheet segmentation distributions","description":"Enterprise review step for grounded audience creation. Classifies respondent-level XLS/XLSX/CSV/SPSS-SAV fields by research role, selects population and segmentation variables while holding outcomes and drivers out, and discovers privacy-safe pairwise relationships. Questionnaire/programming grids are rejected as design evidence instead of being misrepresented as completed respondents. Joint profiles are counted for audit only; rows are never silently sampled. An SPSS .sav is read with its codebook, so value labels, not codes, are reported and declared missing codes count as non-response.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string"},"url":{"type":"string"}}},"segmentationColumns":{"type":"array","items":{"type":"string"},"description":"Column keys returned by an earlier preview. Omit to use the default population and segmentation variables; outcomes and other holdout roles remain excluded."}}}}}},"parameters":[]}},"/api/v1/audiences":{"get":{"responses":{"200":{"description":"Visible Audiences with member readiness and pagination.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"type":"object","required":["id","name","mindCount","minds","currentMemberRole"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"mindCount":{"type":"integer","minimum":0},"minds":{"type":"array","items":{"type":"object","properties":{"readyToChat":{"type":"boolean","description":"The Mind can answer."},"trainingStatus":{"type":"string","enum":["queued","running","completed","failed"],"description":"A failed training attempt reports `queued`: it is retried automatically. `failed` is reported only for a Mind without a system prompt."},"learningInBackground":{"type":"boolean","description":"The Mind can answer and is still learning from its sources in the background."},"fullyTrained":{"type":"boolean","description":"The Mind can answer and its background knowledge step has settled."},"beingRepaired":{"type":"boolean","description":"Present and true while the Mind cannot answer yet because its last training attempt failed and it is retrained automatically. It reports `trainingStatus: queued`; a Study runs without it when enough others answer."}}}},"readiness":{"type":"object","description":"Member rollup. `isReady` is true when every Mind can chat. `startsNow` is true when a Study started now runs at once: nothing is training, and the Minds still being prepared after a failed training attempt are either few enough to leave out (at least one Mind and at least half of the members still answer) or can no longer be retrained automatically; it runs without `leftOut` of them. `learning` counts ready Minds still learning from their sources in the background, and `fullyTrained` is true once every Mind can chat and none is learning.","properties":{"total":{"type":"integer"},"ready":{"type":"integer"},"training":{"type":"integer"},"failed":{"type":"integer","description":"Always 0: a member whose last training attempt failed is being prepared again and counts in `training`. Kept for existing clients."},"isReady":{"type":"boolean"},"startsNow":{"type":"boolean"},"leftOut":{"type":"integer"},"learning":{"type":"integer"},"fullyTrained":{"type":"boolean"}}},"currentMemberRole":{"type":"string","enum":["owner","admin","member","team_member","public_viewer"]},"addOnRequired":{"type":"object","description":"Present only on a paid Marketplace Audience the caller has not subscribed to: asking it or starting a Study with it is refused with 402 `MARKETPLACE_ADDON_REQUIRED` until the add-on is active.","properties":{"priceLabel":{"type":"string","nullable":true,"description":"Monthly add-on price for this caller, e.g. `EUR 49/seat/month`."}}}}}},"pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0}}}}}}}},"400":{"description":"Invalid `search`, `limit` or `offset`."},"401":{"description":"Authentication required."}},"operationId":"listAudiences","summary":"List visible Audiences","description":"Lists owned, public, directly shared, and team-shared Audiences, most recently updated first. `search` (alias `searchQuery`) filters by name within that visibility. Sharing fields are returned only when the caller has collaborator access.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"search","in":"query","required":false,"description":"Case-insensitive substring match against the Audience name (trimmed, at most 200 characters). `pagination.total` counts the matches.","schema":{"type":"string","maxLength":200}},{"name":"searchQuery","in":"query","required":false,"description":"Alias of `search`, matching the `list_audiences` MCP tool. Sent together with `search`, both must be equal.","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}]},"post":{"responses":{"200":{"description":"Idempotent replay of the saved Audience.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedAudienceResponse"}}}},"201":{"description":"The newly created saved Audience.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SavedAudienceResponse"}}}},"400":{"description":"Invalid name or retired request fields."},"401":{"description":"Authentication required."},"403":{"description":"The account cannot create this Audience under its current plan or access permissions."},"404":{"description":"One or more requested Minds are missing or inaccessible."}},"operationId":"createAudience","summary":"Create an Audience from existing Minds","description":"Creates a private saved Audience by default. An optional per-creation idempotency key replays the same Audience with status 200; a new Audience returns 201.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"x-minds-idempotency-key","in":"header","required":false,"description":"Reuse for retries of the same creation. Blank keys and keys longer than 128 characters are ignored.","schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"description":"Non-blank Audience name; surrounding whitespace is trimmed."},"mindIds":{"type":"array","items":{"type":"string"},"default":[],"description":"Accessible existing Mind IDs. Duplicate IDs are deduplicated. Use mindIds, not the retired mindIds field."},"isLinkSharingEnabled":{"type":"boolean","default":false,"description":"Enable only after explicit approval to share a public link."}}}}}}}},"/api/v1/audiences/library":{"get":{"responses":{"200":{"description":"Summary mode returns data with mindCount and membersLoaded=false, plus pageInfo.nextCursor. Membership arrays are partial."},"401":{"description":"Missing or invalid authentication."}},"operationId":"listAudienceLibrary","summary":"List the first-party Audience library projection","description":"Returns owned, followed, directly shared, and team-shared Audiences with caller-specific access fields.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"mode","description":"Opt into bounded pages; omitted preserves the legacy projection.","schema":{"type":"string","enum":["summary"]}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":60}},{"in":"query","name":"after","description":"Opaque nextCursor from the previous page with the same search and sort.","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"type":"string","enum":["name","createdAt","updatedAt"],"default":"updatedAt"}},{"in":"query","name":"direction","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"in":"query","name":"search","description":"Search all visible records, including unloaded pages.","schema":{"type":"string","maxLength":200}},{"in":"query","name":"ids","description":"Comma-separated UUIDs; at most 100.","schema":{"type":"string"}},{"in":"query","name":"fresh","required":false,"description":"Set to 1 after an access change to bypass the short-lived library cache.","schema":{"type":"string","enum":["1"]}}]}},"/api/v1/audiences/lifecycle/stream":{"get":{"responses":{"200":{"description":"Server-sent connected, invalidation, and heartbeat events.","content":{"text/event-stream":{"schema":{"type":"string","description":"SSE frames whose invalidation payload includes durable-state domains to re-read."}}}}},"operationId":"streamAudienceLifecycle","summary":"Stream Audience lifecycle invalidations","description":"User-scoped SSE wakeups for Audience draft, Audience, and Mind revalidation. Events are hints; clients must re-read durable state.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/audiences/limits":{"get":{"responses":{"200":{"description":"Effective Audience creation limits.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"401":{"description":"Missing, invalid, or blocked authentication."},"503":{"description":"Entitlement lookup unavailable. No allowance is returned."}},"operationId":"getAudienceLimits","summary":"Audience creation limits for the authenticated account","description":"Return the Audience size ceilings that apply to this account: the per-Audience plan cap (including a configured team override), the absolute system limit, the custom-size maximum, and per-creation-mode ceilings. scope identifies the authenticated user and entitlement team; allowance identifies the plan default, team override or legacy unlimited conversion; checkedAt is the observation time. These are per-Audience sizes, not a total workspace allowance or remaining credits. Match scope to the intended account before attributing these limits to it. Call this before creating an Audience to learn the real limits rather than discovering them from a 403. Mode ceilings come in two kinds and they are not interchangeable: `automaticSizingCeiling` bounds the size the server picks when no memberCount is given, while `explicitCountCeiling` bounds a size you state — only \"balanced\" has one: a stated size above it moves to a deeper mode the plan includes, or is built at the ceiling with a note; it is never refused.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/audiences/source-import":{"post":{"responses":{"200":{"description":"Imported files and optional reviewed grounding snapshot.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Invalid text, grounding, source reference or foreign file."},"401":{"description":"Authentication required."},"413":{"description":"Import is too large."},"502":{"description":"Source storage unavailable; retrying the same import is safe."}},"operationId":"importAudienceSources","summary":"Import supplied UTF-8 audience research sources","tags":["Audiences"],"description":"Store up to 20 caller-supplied text, Markdown, CSV or JSON files as durable account-owned uploads. The 5 MB per-file and 12 MB combined limits include existing file references. Optional groundingJson binds explicit supplied chart percentages to these files and returns a normalized snapshot/checksum for groundingPreview and creation. No research, Minds, or Audience is created. Identical file imports replay the same content-addressed URLs after storage confirmation.","security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"array","maxItems":20,"items":{"type":"object","required":["name","content"],"properties":{"name":{"type":"string","maxLength":200},"content":{"type":"string","maxLength":5242880}}}},"existingFiles":{"type":"array","maxItems":20,"items":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string"},"url":{"type":"string"}}}},"groundingJson":{"type":"string","maxLength":2000000}}}}}},"parameters":[]}},"/api/v1/audiences/validation-benchmarks":{"get":{"responses":{"200":{"description":"Candidates.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"summary":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Audience not found."}},"operationId":"listValidationBenchmarks","summary":"Find surveys to validate an Audience against (experimental)","description":"Experimental. Without `audienceId`: every public survey the evidence pool holds whole (published statistics tables, surveys computed from published microdata, any imported survey), as `kind: public` with a `study:` id. With `audienceId`: the candidates for that Audience, best first. A candidate’s `population.sampleSize` is `null` when the source gives no survey-wide respondent count; question bases are retained independently. Each candidate carries `comparability.populationMatch`: how far the Audience is from the surveyed population (0–100 per variable and overall, weighted by how much each variable moves the survey's answers; `afterReweightingScore` once answers are narrowed to the Audience's mix where the survey reports by that variable; `checkedShare`, the part of that answer-relevant variation the check could cover). Respondent datasets attached to the Audience come first (`kind: audience_dataset`, use its `id` as `dataset.sourceId`). Surveys you supplied in earlier validations (uploaded files, datasets or your own shares) come back as `kind: saved`, visible only to you. Published surveys (`kind: public`, with `sourceUrl`), whether the evidence pool holds them whole (`study:` ids) or a web search read them (`discovered:` ids; use the `id` as `benchmarkId`; ids handed out earlier, such as a survey's bare id, still resolve) follow, ranked by how well the survey population matches the Audience (`direct`, then `proxy`, `not_comparable` last) and then by topic similarity to the Audience's name and brief. Within a tier, surveys whose geography could be checked come first. `summary.recommended` is the first own dataset or the first fitting survey with checked geography; `summary.state` is `available`, `unverified_only` (surveys fit but none could be placed geographically: the Minds carry no place and the brief names none, so the caller chooses) or `no_comparable_survey`; a survey of a different population is never recommended. A survey is offered as a fit only once a model has compared who it asked with the Audience; until then it is `not_comparable` with that reason. A survey whose questions clearly do not bear on what the Audience is about is `not_comparable` too, unless it asked exactly the Audience's people (`same`), whose answers are evidence whatever they were asked. The web search (`POST /audiences/validation-benchmarks/search`) makes that comparison for every survey on offer, so fitting candidates appear while it runs. A survey is offered only when a validation could score it for this Audience, by the same gate the validation applies before it asks: at least 10 Minds answer it and it publishes answers to at least one question. Short surveys pool: a validation needs 8 questions in all, not per survey. A survey of part of the Audience (`relation.kind: part`) is asked only of the Minds whose profile shows they belong to the people it asked: it carries `respondents` once the search has read them (`selected` of `audienceMembers` Minds, and `caveats`, survey criteria the Minds do not state, which are not checked), and until then, or when fewer than 10 fit, it is `not_comparable` with that reason. Every candidate carries `scoring`: `scorable`, `eligibleMinds` (null while unread), `audienceMinds`, `scorableQuestions` and `expectedEvidence` (eligible Minds × scorable questions × how much a question of that relation counts). Offered surveys are ranked with evidence about the Audience's own people (`same`, `part`) first, then by `expectedEvidence`, then by the keys above. `summary.search` is the Audience's latest web search (`POST /audiences/validation-benchmarks/search`), so a caller can poll it and read verified candidates while the search runs.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"audienceId","required":false,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"searchOnly","required":false,"schema":{"type":"boolean"},"description":"Requires audienceId. Read only summary.search without loading members or ranking candidates; data is empty. Omit this parameter to receive verified candidates progressively while discovery runs."}]}},"/api/v1/audiences/validation-benchmarks/search":{"post":{"responses":{"202":{"description":"Search queued or reused.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","additionalProperties":true}}}}}},"401":{"description":"Unauthorized."},"403":{"description":"No included validation is left and the synthetic responses left cannot pay for the smallest run: the standard plan-limit error."},"404":{"description":"Audience not found or not editable by the caller."}},"operationId":"searchValidationBenchmarks","summary":"Search the web for surveys to validate an Audience against (experimental)","description":"Experimental. Needs an included validation left this month, or synthetic responses for the smallest validation run (8 questions for every ready Mind). Starts a background search for published survey results that match the Audience: queries are planned from its name, brief and member composition, the web and the public source bank are searched, and each source is read once. A source becomes a benchmark only when every kept share is backed by a verbatim passage of the source, the question wording appears in it, single-choice shares add up, and a base is stated. Results are cached per source text and shared with later searches from any Audience. Returns 202 with the search; poll `GET /audiences/validation-benchmarks?audienceId=` (its `summary.search`) and the found surveys appear as `kind: public` candidates with `discovered:` ids. The search also judges, for every survey on offer, who it asked and whether its questions bear on the Audience. A search already running, or completed within the last day with every offered survey judged, is returned instead of starting another unless `force` is true.","tags":["Audiences"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["audienceId"],"properties":{"audienceId":{"type":"string","format":"uuid"},"force":{"type":"boolean"}}}}}},"parameters":[]}},"/api/v1/auth/me":{"get":{"responses":{"200":{"description":"The authenticated user.","content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","format":"uuid","description":"User ID the API key belongs to."}}},"example":{"id":"550e8400-e29b-41d4-a716-446655440000"}}}},"401":{"description":"Missing or invalid API key (`Unauthorized`)."}},"operationId":"getAuthenticatedUser","summary":"Identify the authenticated user","description":"Return the user ID that the presented API key belongs to. Use it to confirm a key is valid at startup, after rotating keys, or to learn which account an integration is acting as. Any rejected credential returns the same generic 401 `Unauthorized`; the API does not distinguish a missing key from an invalid or revoked one.","tags":["Auth"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/billing/catalog":{"get":{"responses":{"200":{"description":"Subscription prices, response-credit packs and eligibility."}},"operationId":"getBillingCatalog","summary":"Read existing Stripe subscription and response-credit options","tags":["Billing"],"description":"Authenticated catalog from the current billing account, with existing prices and purchase eligibility. Final taxes and discounts are confirmed during Checkout. Use the returned Stripe price IDs to start checkout.","parameters":[{"name":"currency","in":"query","required":false,"schema":{"type":"string","enum":["eur","usd"]},"description":"Explicit currency preference shared with UI and MCP. Omit for location-based defaults."},{"name":"billingCountry","in":"query","required":false,"schema":{"type":"string"},"description":"Billing-address country for a new PAYG workspace. Existing billing ownership remains unchanged."},{"name":"includeInvoices","in":"query","required":false,"schema":{"type":"boolean"},"description":"Include recent Stripe invoices for an authorized billing owner or admin. Omitted by default."}]}},"/api/v1/billing/checkout":{"post":{"responses":{"200":{"description":"Stripe Checkout URL and session ID; payment is confirmed through Stripe webhooks."}},"operationId":"startBillingCheckout","summary":"Start subscription, response-credit or automatic recharge setup checkout","tags":["Billing"],"description":"Uses existing Stripe prices and billing ownership. Return the URL to the buyer to complete address, tax and payment consent. This does not confirm payment. Send a stable Idempotency-Key for all purchase retries.","parameters":[{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","additionalProperties":false,"required":["kind","legalAcceptance"],"properties":{"kind":{"const":"subscription"},"priceId":{"type":"string"},"planType":{"enum":["premium","team"]},"startTrial":{"type":"boolean","description":"Legacy field. New Starter subscriptions and trials are retired; true is refused."},"quantity":{"type":"integer","minimum":1},"billingCountry":{"type":"string"},"currency":{"enum":["usd","eur"]},"legalAcceptance":{"type":"object","required":["termsAccepted","withdrawalConsent"],"additionalProperties":false,"properties":{"termsAccepted":{"const":true},"withdrawalConsent":{"const":true}}}}},{"type":"object","additionalProperties":false,"required":["kind","priceId"],"properties":{"kind":{"const":"response_credits"},"priceId":{"type":"string"},"amountMinor":{"type":"integer","minimum":1,"maximum":99999999,"description":"Optional custom budget in minor currency units at the responseCredits.customTopUp source price. The server quotes whole responses and charges their rounded total, never unused budget."},"billingCountry":{"type":"string","description":"Billing-address country, required for a new PAYG workspace."}}},{"type":"object","additionalProperties":false,"required":["kind","priceId","amountMinor","thresholdAmountMinor","monthlyAmountLimit"],"properties":{"kind":{"const":"auto_recharge"},"priceId":{"type":"string","description":"Current responseCredits.customTopUp source price."},"amountMinor":{"type":"integer","minimum":1,"maximum":99999999,"description":"Custom recharge budget in the source currency, quoted as whole responses."},"thresholdAmountMinor":{"type":"integer","minimum":0,"maximum":99999999,"description":"Low balance threshold converted to whole responses at the same rate; below the recharge amount."},"monthlyAmountLimit":{"oneOf":[{"type":"integer","minimum":1,"maximum":99999999},{"const":"none"}],"description":"Automatic purchase cap per UTC calendar month, in the saved currency at the published tax basis. EUR includes VAT; USD excludes added sales tax. Must cover at least one recharge; none requires explicit uncapped consent. Manual purchases are independent."}}}]}}}}}},"/api/v1/billing/invoices/{invoiceId}/pay":{"post":{"responses":{"200":{"description":"Stripe confirmed invoice payment. Fulfillment follows the signed webhook."},"402":{"description":"MPP or x402 payment challenge."},"409":{"description":"Invoice unavailable, changed, or payment needs reconciliation."}},"operationId":"payBillingInvoice","summary":"Pay an owned, manually collected Stripe invoice with MPP or x402","tags":["Billing"],"description":"Supports open send_invoice invoices for subscriptions and response-credit purchases. Automatic collection stays on Stripe hosted invoices. The 402 challenge quotes the actual remaining amount including tax and discounts. Keep Minds Bearer authentication; send MPP credentials in Payment-Authorization, or x402 in PAYMENT-SIGNATURE. Native MPP clients may instead use Authorization: Payment with Minds-Authorization: Bearer for account identity. x402 requires mppx route-bound nonces and a configured facilitator; USDC is available only for USD invoices. Reuse the original credential after uncertain responses.","parameters":[{"name":"invoiceId","in":"path","required":true,"schema":{"type":"string"}},{"in":"header","name":"Minds-Authorization","schema":{"type":"string"}},{"in":"header","name":"Payment-Authorization","schema":{"type":"string"}},{"in":"header","name":"PAYMENT-SIGNATURE","schema":{"type":"string"}}],"x-payment-info":{"offers":[{"intent":"charge","method":"stripe","amount":null,"currency":"usd","description":"Exact remaining invoice amount; requires a business profile on the owning Stripe account."},{"intent":"charge","method":"stripe","amount":null,"currency":"eur","description":"Exact remaining invoice amount; requires a business profile on the owning Stripe account."}]}}},"/api/v1/chats/{chatId}":{"delete":{"responses":{"204":{"description":"Chat deleted. No body."},"400":{"description":"`Chat ID is required` or `Invalid chat ID format` (not a UUID)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"The chat exists but the caller is not its owner (`Forbidden`)."},"404":{"description":"Chat missing or no longer owned at the final write (`Chat not found`)."},"500":{"description":"Internal server error."}},"operationId":"deleteChat","summary":"Delete a chat","description":"Permanently delete a stateful chat created with `POST /v1/chats` together with its messages, Mind assignments and Study Audience memberships. Only the chat owner may delete it; the Minds and Audiences themselves are untouched. Use this to clean up finished conversations. Returns 204 with an empty body.","tags":["Chat"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"chatId","required":true,"description":"Chat UUID (the `data.id` returned by `POST /v1/chats`).","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/chats/{chatId}/messages":{"post":{"responses":{"200":{"description":"Reply generated (or system note stored). Discriminate on the presence of `messages` (multi-Mind), `outputData` (Study), `role: \"system\"` (system note) or `content` (single Mind).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatMessageResponse"},"examples":{"singleMind":{"summary":"Single-Mind reply","value":{"content":"Recent advancements include perovskite cells with 30%+ efficiency…","messageId":"cmnkbsddh00033v01ptk9t4et"}},"structured":{"summary":"Single-Mind reply with structured output","value":{"content":"{\"score\":8,\"reason\":\"Concrete benefit, memorable rhythm.\"}","messageId":"cmnkbsddh00033v01ptk9t4et","parsed":{"score":8,"reason":"Concrete benefit, memorable rhythm."}}},"toolCall":{"summary":"Single-Mind reply requesting a tool call","value":{"content":"","messageId":"cmnkbsddh00033v01ptk9t4et","tool_calls":[{"id":"call_abc123","name":"create_meeting","arguments":{"startsAt":"2026-09-08T10:00:00+02:00","durationMinutes":30}}]}},"multiMind":{"summary":"Multi-Mind replies","value":{"messages":[{"content":"From a growth angle…","messageId":"cmnkbsddh00033v01ptk9t4et","mind":{"id":"4774888e-0a03-40d7-979b-39b47c4c049c","name":"Ada"}},{"content":"I disagree on timing…","messageId":"cmnkbsddh00043v01abcd1234","mind":{"id":"9bf44ab0-9d83-42ec-b941-c0ab7610e949","name":"Grace"}}]}},"study":{"summary":"Study chat aggregated output","value":{"outputData":{"title":"How likely are you to recommend this product?","type":"scale","audiences":[{"audience":"Gen Z shoppers","value":"7.4","answers":[{"value":"8","persona":"Mia","message":"Pretty likely — the onboarding was quick."}]}]}}},"system":{"summary":"System note stored","value":{"messageId":"cmnkbsddh00053v01sys00001","role":"system"}}}}}},"202":{"description":"Study chats only: some Minds of the attached Audiences are still training, so the message was queued as a durable Study question instead of answered now. It runs once they are ready (`status: preparing`, `waitingFor`) and its answer is added to the chat transcript (read it with GET /v1/chats/{chatId}/messages). Minds being retrained answer with their current version, so only brand-new Minds are waited for.","content":{"application/json":{"schema":{"type":"object","required":["status","questionBlockId","clientRequestId"],"properties":{"status":{"type":"string","enum":["queued","preparing"]},"waitingFor":{"type":"integer","minimum":1,"description":"Minds the question waits for before it runs."},"jobId":{"type":"string"},"questionBlockId":{"type":"string"},"clientRequestId":{"type":"string"},"leftOutMinds":{"type":"array","items":{"type":"object"},"description":"Minds whose training keeps failing (they are retried automatically) and that the question runs without; they are retrained automatically."}}}}}},"400":{"description":"Validation error: `Message content is required`, `Invalid chat ID format`, `role must be \"user\" or \"system\"`, `Both model and provider required for override`, `Invalid provider: '{provider}'. Allowed: anthropic, openai, google.`, `Invalid model '{model}' for provider '{provider}'.`, invalid `response_format` / `tools` / `tool_choice` (e.g. `tools[0].name 'WEB_SEARCH' conflicts with an internal tool name`, `Maximum 128 tools allowed`), `Study must have at least one assigned Mind`, or for Study chats `Study has no audiences assigned` / `Study audiences have no Mind members`."},"401":{"description":"Missing or invalid API key."},"402":{"description":"Study chats only: an attached Audience is a paid marketplace add-on you have not subscribed to (`data.code: MARKETPLACE_ADDON_REQUIRED`)."},"403":{"description":"Plan limit reached (`data.code: PLAN_LIMIT`). One of: the per-chat user-message cap (`limitType: messages`, `{Plan} plan limit reached`); the started-Study cap when this is the first user message in the chat (`limitType: flows`); the monthly synthetic-response allowance, reserved before generation and charged per replying Mind (`limitType: responses`, includes `periodEnd`); or for Study chats an Audience above the per-Audience member cap (`limitType: audienceMembers`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatPlanLimitError"}}}},"404":{"description":"Chat missing, owned by another caller, or unavailable under current managed-workspace grants; also `User profile not found`."},"409":{"description":"A chat Mind is not ready (`data.code: SPARK_NOT_READY`), or, for Study chats, no Mind of the attached Audiences can answer and none can be retrained (`data.code: PANEL_MINDS_NOT_READY`, `data.cause: no_mind_can_answer`), naming the Minds; nothing ran and nothing was charged. Minds still training never cause this 409 on a Study chat: the message is queued (202). Minds still being prepared after a failed training attempt do not block it: with at least one Mind and at least half of the Minds it asks able to answer, it runs without them (`leftOutMinds`) and they are retrained automatically; with fewer, they are retrained first and the message is queued until they are ready.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatStudyMindsNotReadyError"}}}},"413":{"description":"JSON request body exceeds 1 MiB."},"500":{"description":"Chat storage or generation failed, or for multi-Mind chats `No Minds responded`."},"503":{"description":"Usage metering is temporarily unavailable (`data.code: USAGE_METERING_UNAVAILABLE`); nothing was generated or charged, retry later."}},"operationId":"sendChatMessage","summary":"Send a message to a chat","description":"Append a turn to a stateful chat and receive the reply. The server persists every message, sends the last 8 turns verbatim and compresses older ones into a rolling summary, so you only ever send the new message. The response shape depends on how the chat was created: a single-Mind chat returns `content` + `messageId` (plus `parsed` / `tool_calls` when structured output or tools were requested); a multi-Mind chat returns `messages[]` with one entry per Mind the moderator let speak (each Mind at most once per turn, up to 5 turns); a Study chat fans the message out to every ready Mind in the attached Audiences and returns aggregated `outputData`. Send `role: \"system\"` to store a note in the transcript without triggering any reply. Only the chat owner can post. This endpoint always responds with buffered JSON; for progress streaming use `POST /v1/minds/{mindId}/completion` with `responseMode: \"stream\"`.","tags":["Chat"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"chatId","required":true,"description":"Chat UUID returned by `POST /v1/chats`.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatMessageRequest"},"examples":{"basic":{"summary":"Plain user message","value":{"content":"What are the top marketing trends this year?"}},"withEndUser":{"summary":"Name the end user and pin the model","value":{"content":"Which of those fits a small budget?","endUserName":"Lena","model":"claude-sonnet-5-5","provider":"anthropic"}},"structured":{"summary":"Structured output (single-Mind chat only)","value":{"content":"Rate this tagline from 1 to 10 and explain: \"Ship faster, sleep better.\"","response_format":{"type":"json_schema","json_schema":{"name":"tagline_rating","schema":{"type":"object","properties":{"score":{"type":"integer","minimum":1,"maximum":10},"reason":{"type":"string"}},"required":["score","reason"]}}}}},"tools":{"summary":"Function calling (single-Mind chat only)","value":{"content":"Book a 30 minute call with me tomorrow at 10:00.","tools":[{"name":"create_meeting","description":"Create a calendar meeting","parameters":{"type":"object","properties":{"startsAt":{"type":"string","format":"date-time"},"durationMinutes":{"type":"integer"}},"required":["startsAt","durationMinutes"]}}],"tool_choice":"auto"}},"systemNote":{"summary":"Store a system note without a reply","value":{"role":"system","content":"The user has switched to the enterprise plan."}}}}}}}},"/api/v1/chats":{"post":{"responses":{"200":{"description":"Existing response thread resumed.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ChatCreated"}}}}}},"201":{"description":"Chat created. Mind chats return `data.minds`; Study chats return `data.type: \"study\"` and `data.audiences`.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"oneOf":[{"$ref":"#/components/schemas/ChatCreated"},{"$ref":"#/components/schemas/ChatStudyCreated"}]}}},"examples":{"singleMind":{"summary":"Mind chat","value":{"data":{"id":"601af953-3837-49c1-a31e-4fdbfa82ac04","name":"Research Session","description":null,"createdAt":"2026-04-04T12:45:24.078Z","minds":[{"id":"4774888e-0a03-40d7-979b-39b47c4c049c","name":"Ada Lovelace","discipline":"Mathematics"}]}}},"study":{"summary":"Study chat","value":{"data":{"id":"7c1d2c0e-3b1a-4c0f-9f2e-0e6a1b2c3d4e","name":"Onboarding feedback","type":"study","audiences":[{"id":"550e8400-e29b-41d4-a716-446655440000","name":"Gen Z shoppers","mindCount":25}],"createdAt":"2026-04-04T12:45:24.078Z"}}}}}}},"400":{"description":"Validation error: `At least one of mindId, mindIds, or audienceIds is required`, `At least one Mind ID is required`, or a retired field name (rejected with a message naming its replacement)."},"401":{"description":"Missing or invalid API key."},"402":{"description":"Study chats only: an attached Audience is a paid marketplace add-on you have not subscribed to (the message names the Audience and its price; `data.code: MARKETPLACE_ADDON_REQUIRED` with `audienceId`, `audienceName`, `addOnId`, `priceLabel`)."},"403":{"description":"Plan limit reached (`data.code: PLAN_LIMIT`). Either the started-Study cap (`limitType: flows`, `context: chatCreation` or `studyCreation`, status message `{Plan} plan includes N Studies. Upgrade to … to create more Studies.`) or, for Study chats, an attached Audience exceeds the per-Audience member cap (`limitType: audienceMembers`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatPlanLimitError"}}}},"404":{"description":"A referenced Mind or Audience does not exist or is not accessible: `Minds not found: {ids}`, `No valid Minds found`, `Audiences not found: {ids}`. Also `User profile not found` when the API key owner has no profile."},"413":{"description":"JSON request body exceeds 1 MiB."},"500":{"description":"Internal server error."}},"operationId":"createChat","summary":"Create a stateful chat","description":"Create a persistent conversation whose history, context compression and rolling summary are managed server-side, then post turns with `POST /v1/chats/{chatId}/messages`. Pick exactly one shape: `mindId` for a 1:1 chat with a single Mind, `mindIds` for a multi-Mind conversation where a moderator decides which Mind answers each turn, or `audienceIds` for a Study chat that fans every message out to all Minds in the attached Audiences and returns aggregated output. Use this when you want the server to remember the conversation; use `POST /v1/minds/{mindId}/completion` when you manage history yourself. Minds must be owned by you, public, or shared with your team; Audiences must be ones you own, belong to, or that are public or shared with your team. Retired field names are rejected with 400 naming the replacement.","tags":["Chat"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCreateRequest"},"examples":{"singleMind":{"summary":"1:1 chat with one Mind","value":{"name":"Research Session","mindId":"4774888e-0a03-40d7-979b-39b47c4c049c"}},"multiMind":{"summary":"Multi-Mind conversation","value":{"name":"Launch debate","mindIds":["4774888e-0a03-40d7-979b-39b47c4c049c","9bf44ab0-9d83-42ec-b941-c0ab7610e949"]}},"study":{"summary":"Study chat over Audiences","value":{"name":"Onboarding feedback","description":"Gen Z shoppers","audienceIds":["550e8400-e29b-41d4-a716-446655440000"]}}}}}},"parameters":[]}},"/api/v1/events":{"get":{"responses":{"200":{"description":"Event definitions, argument filters and payload schemas."},"401":{"description":"Unauthorized."}},"operationId":"listReadinessEvents","summary":"List Audience and Study readiness webhook events","description":"Protocol-specific subscriptions let connected clients react to the same saved readiness state as the workspace. Supports webhook delivery only, with no event-history replay.","tags":["Events"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/events/subscribe":{"post":{"responses":{"200":{"description":"Subscription id, finite refreshBefore, null cursor and truncated=false."},"400":{"description":"Invalid event, arguments or callback."},"403":{"description":"Resource or scope denied."},"404":{"description":"Resource not found."},"502":{"description":"Callback verification failed; data.reason categorizes the failure."}},"operationId":"subscribeReadinessEvent","summary":"Subscribe to one Audience creation or Study run","description":"Accepts an event name, arguments and webhook delivery with HTTPS url and a Standard Webhooks whsec_ secret. The signed callback challenge must succeed before activation. ttlMs requests a lifetime, capped at 24 hours; null grants the finite server default. cursor must be null: historical event replay is unavailable. Repeating the same authenticated principal, callback, event and arguments refreshes the same subscription.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","arguments","delivery"],"additionalProperties":false,"properties":{"name":{"type":"string","enum":["audience.creation.finished","study.run.finished"]},"arguments":{"type":"object","description":"Audience: operationId (UUID). Study: studyId and runId (UUIDs). Exact argument schemas are returned by GET /api/v1/events."},"delivery":{"type":"object","required":["mode","url","secret"],"additionalProperties":false,"properties":{"mode":{"type":"string","enum":["webhook"]},"url":{"type":"string","format":"uri","description":"Public HTTPS callback; redirects and private addresses are rejected."},"secret":{"type":"string","description":"whsec_ followed by base64 encoding of a 24–64 byte signing key."}}},"ttlMs":{"type":["integer","null"],"minimum":1,"description":"Requested lifetime; capped at 86400000 ms. Omitted/null grants the finite default."},"cursor":{"type":"null"}}}}}},"tags":["Events"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/events/unsubscribe":{"post":{"responses":{"200":{"description":"An empty data object."},"400":{"description":"Invalid subscription identity."},"401":{"description":"Unauthorized."}},"operationId":"unsubscribeReadinessEvent","summary":"Stop one readiness webhook subscription","description":"Accepts the original event name, arguments and webhook callback URL. Idempotently stops the subscription owned by the current credential principal. Does not cancel the underlying Audience creation or Study run.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","arguments","delivery"],"additionalProperties":false,"properties":{"name":{"type":"string","enum":["audience.creation.finished","study.run.finished"]},"arguments":{"type":"object","description":"The exact original event filter returned by GET /api/v1/events."},"delivery":{"type":"object","required":["mode","url"],"additionalProperties":false,"properties":{"mode":{"type":"string","enum":["webhook"]},"url":{"type":"string","format":"uri"}}}}}}}},"tags":["Events"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/integrations/figma/comments":{"post":{"responses":{"200":{"description":"Preview or delivery receipts. Partial delivery must be inspected before retrying."},"401":{"description":"Authentication required"},"409":{"description":"Comment consent, current preview or completed evidence required"},"422":{"description":"Unsupported frame geometry or missing positioned evidence"}},"operationId":"exportFigmaFeedback","summary":"Preview or publish completed Study feedback as native Figma comments","tags":["Integrations"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["studyId","runId","frameUrl"],"properties":{"studyId":{"type":"string","format":"uuid"},"runId":{"type":"string","format":"uuid"},"frameUrl":{"type":"string","minLength":1,"maxLength":2000,"description":"Figma design frame link with node-id."},"expectedNodeId":{"type":"string","pattern":"^[0-9]+:[0-9]+$"},"action":{"type":"string","enum":["preview","publish"],"default":"preview"},"feedback":{"type":"string","enum":["summary","heatmap"],"default":"summary"},"messageId":{"type":"string","minLength":1,"maxLength":200,"description":"Completed image heatmap message, required for heatmap feedback."},"assetKey":{"type":"string","maxLength":2000,"description":"Image asset key; use an empty string for the primary image heatmap."},"sceneId":{"type":"string","minLength":1,"maxLength":200},"previewHash":{"type":"string","pattern":"^[a-f0-9]{64}$","description":"Current preview hash, required for publishing."},"commentKeys":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"string","pattern":"^[a-f0-9]{64}$"},"description":"Explicitly reviewed comment keys, required for publishing."}}}}}},"parameters":[]}},"/api/v1/minds/{mindId}":{"delete":{"responses":{"204":{"description":"Mind deleted. Empty body."},"400":{"description":"`Invalid Mind ID format` (not a UUID)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Mind not found`: the Mind does not exist or is not owned by the caller."},"500":{"description":"`Failed to delete Mind`: the cleanup workflow failed; the Mind may still exist."}},"operationId":"deleteMind","summary":"Delete a Mind","description":"Permanently delete one Mind you own together with its knowledge, patterns, portfolio items, chat history, and stored files. Only the owner (the account that created the Mind) can delete it; Minds that are merely shared with you, or visible through a team, Audience, or Study, return 404 `Mind not found` rather than 403. This cannot be undone. To delete several Minds with the same cleanup semantics use `DELETE /v1/minds` with a `mindIds` body.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}]},"get":{"responses":{"200":{"description":"Mind detail.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/MindDetail"}}}}}},"400":{"description":"Invalid Mind ID format (not a UUID)."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller does not have access to this Mind."},"404":{"description":"Mind does not exist."},"500":{"description":"Internal server error."}},"operationId":"getMind","summary":"Get a Mind by ID","description":"Retrieve full details for a single Mind, including its stored profile attributes, generated system prompt, sharing settings, voice clone status, and knowledge-item count. Returns 403 if the caller is not the owner, team member, direct member, or the Mind is not public.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}]},"put":{"responses":{"200":{"description":"The updated Mind.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","name","description","type","discipline","systemPrompt","sourcePolicy","tags","isPublic","isLinkSharingEnabled","isSharedWithTeam","publicShareId","profileImageUrl","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["creative","expert","user"]},"discipline":{"type":["string","null"]},"systemPrompt":{"type":"string","description":"Full system prompt after the update."},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"],"description":"Persisted source policy."},"tags":{"type":"array","items":{"type":"string"}},"isPublic":{"type":"boolean","description":"Always false for individual Minds."},"isLinkSharingEnabled":{"type":"boolean"},"isSharedWithTeam":{"type":"boolean"},"publicShareId":{"type":["string","null"],"format":"uuid","description":"Share token; set only while link sharing is enabled."},"profileImageUrl":{"type":["string","null"],"format":"uri","description":"Avatar image; resolved to an absolute URL."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"description":"`Invalid Mind ID format`, `Name must be between 2 and 100 characters`, `sourcePolicy must be one of: auto, knowledge_only` or `sourcePolicy=request_only is supported only for Study execution`, or `No valid fields to update` (body contained none of the editable fields)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"`Forbidden`: caller is not the owner, a direct member, or a member of the team the Mind is shared with."},"404":{"description":"`Mind not found`."},"500":{"description":"Internal server error."}},"operationId":"updateMind","summary":"Update a Mind","description":"Partially update an existing Mind. Send only the fields you want to change; omitted fields are left untouched, and at least one recognised field must be present. Callable by the owner, by a direct Mind member, or by a member of the team the Mind is shared with; everyone else gets 403 `Forbidden`. Existence and permission are checked before the body is validated, so a missing or forbidden Mind always yields 404/403 rather than a field error. Note that `isPublic` is accepted for backward compatibility but always stored as `false` (individual Minds can no longer be made public; share an Audience instead), and `type` values outside `creative`, `expert`, `user` are normalised to `creative`. Sharing changes: `isLinkSharingEnabled: true` keeps or generates the `publicShareId`, `false` clears it; `isSharedWithTeam` (owner or Mind admin) shares the Mind with the owner's team or removes that access.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateMindRequest"},"examples":{"systemPrompt":{"summary":"Replace the system prompt","value":{"systemPrompt":"Du bist ein erfahrener Handwerker im Sanitärbereich. Antworte immer aus deiner persönlichen Praxiserfahrung."}},"profile":{"summary":"Update several profile fields","value":{"name":"Senior Plumber Expert","description":"Expert plumber with 20 years of experience","discipline":"Plumbing & Sanitary Installation","tags":["plumbing","sanitary","renovation"]}},"sharing":{"summary":"Enable link sharing and lock answers to Mind knowledge","value":{"isLinkSharingEnabled":true,"sourcePolicy":"knowledge_only"}},"team":{"summary":"Share with the owner's team","value":{"isSharedWithTeam":true}}}}}}}},"/api/v1/minds/{mindId}/collaborators/{userId}":{"delete":{"responses":{"200":{"description":"Removed.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid id, or the user is the owner (`COLLABORATOR_IS_OWNER`)."},"401":{"description":"Unauthorized."},"403":{"description":"The caller can see the Mind but does not manage its sharing (`COLLABORATORS_MANAGER_ONLY`)."},"404":{"description":"Mind not found or not visible to the caller, or the person is not a collaborator."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"removeMindCollaborator","summary":"Remove a collaborator from a Mind","description":"Removes the person's membership and revokes their invitations for this Mind in one step, so an old invitation link cannot restore access. Nobody is emailed. Only the Mind owner or a Mind admin may call it; the owner cannot be removed.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"mindId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds/{mindId}/collaborators":{"get":{"responses":{"200":{"description":"Collaborators of the Mind.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","required":["userId","email","name","role","joinedAt"],"properties":{"userId":{"type":"string","format":"uuid","description":"Pass to DELETE …/collaborators/{userId}."},"email":{"type":["string","null"],"format":"email"},"name":{"type":["string","null"]},"role":{"type":"string","description":"Role granted by the accepted invitation."},"joinedAt":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Invalid id."},"401":{"description":"Unauthorized."},"403":{"description":"The caller can see the Mind but does not manage its sharing (`COLLABORATORS_MANAGER_ONLY`)."},"404":{"description":"Mind not found or not visible to the caller."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"listMindCollaborators","summary":"List the people who accepted an invitation to a Mind","description":"Returns every collaborator of the Mind (people who accepted an email invitation), oldest first, without the owner. Pending invitations are listed by the invitations endpoints. Only the Mind owner or a Mind admin may call it; anyone else who can see the Mind gets 403.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"mindId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds/{mindId}/completion":{"post":{"responses":{"200":{"description":"Reply generated. `application/json` for `responseMode: \"sync\"` (default); `text/event-stream` for `responseMode: \"stream\"`, where the `result` frame carries the identical `MindCompletionResponse` payload and failures after opening the stream (including 401/403/404/409/429) are reported as an `error` frame followed by `done`. Body size/shape failures return HTTP 400/413 before streaming.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MindCompletionResponse"},"examples":{"text":{"summary":"Text reply with citations","value":{"messageId":"msg_550e840029b141d4a716446655440000","content":"Recent advancements include perovskite cells with 30%+ efficiency[[CITE:0]]…","metadata":{"ragCitations":[{"id":"9bf44ab0-9d83-42ec-b941-c0ab7610e949","displaySource":"Mind knowledge","similarity":0.89,"sourceType":"mind_knowledge"}],"answerProvenance":{"origin":"cited_sources","sourcePolicy":"auto","retrievalAttempted":true,"retrievalChunksFound":4,"evidenceSourceTypes":["mind_knowledge"],"fallbackStatus":"grounded","unsupported":false,"recordedAt":"2026-09-07T10:00:00.000Z","verifier":"single-mind-answer-provenance-v1"}}}},"structured":{"summary":"Structured output","value":{"messageId":"msg_550e840029b141d4a716446655440001","content":"{\"sentiment\":\"positive\",\"confidence\":0.95}","parsed":{"sentiment":"positive","confidence":0.95}}},"toolCall":{"summary":"Tool call requested","value":{"messageId":"msg_550e840029b141d4a716446655440002","content":"","tool_calls":[{"id":"call_abc123","name":"get_weather","arguments":{"city":"Berlin","units":"celsius"}}]}},"knowledgeOnly":{"summary":"Knowledge-only reply","value":{"messageId":"msg_550e840029b141d4a716446655440003","content":"The study describes classroom smartphone rules as…","metadata":{"sourcePolicy":"knowledge_only","ragCitations":[{"id":"abc123","displaySource":"teacher-archetypes.pdf","sourceType":"mind_knowledge","similarity":0.81}],"knowledgeRetrieval":{"status":"grounded","retrievalAttempted":true,"chunksFound":4,"sourceCount":1,"sources":[{"title":"teacher-archetypes.pdf","sourceType":"mind_knowledge"}]}}}}}},"text/event-stream":{"schema":{"type":"string","description":"Server-Sent Events. Frames are `event: <name>` + `data: <JSON>`; `data` payloads match `MindCompletionSseEvent`. A 2 KB padding comment and a `start` frame are sent immediately, `: heartbeat` comments every 15 s while generating, then exactly one `result` (or `error`) frame followed by `done`."},"examples":{"stream":{"summary":"Full stream","value":"event: start\ndata: {\"type\":\"start\",\"timestamp\":1757239200000}\n\n: heartbeat\n\nevent: result\ndata: {\"messageId\":\"msg_550e840029b141d4a716446655440000\",\"content\":\"The study describes…\",\"metadata\":{\"sourcePolicy\":\"knowledge_only\"}}\n\nevent: done\ndata: {\"type\":\"done\"}\n\n"},"error":{"summary":"Failure inside the stream","value":"event: start\ndata: {\"type\":\"start\",\"timestamp\":1757239200000}\n\nevent: error\ndata: {\"type\":\"error\",\"status\":409,\"message\":\"This Mind is still being prepared\"}\n\n"}}}},"x-event-schema":{"$ref":"#/components/schemas/MindCompletionSseEvent"}},"400":{"description":"Validation error. Caller message history cannot supply provider options, provider-owned references, provider execution or approval state. Path/body: `Mind ID is required`, `Invalid Mind ID format`, `responseMode must be 'sync' or 'stream'`, `sourcePolicy must be one of: auto, request_only, knowledge_only`, `citationMarkers must be one of: inline, none`, `messages[{i}].content must be a non-empty string for role \"user\" (omit messages or send an empty array for the greeting bootstrap)`, `sourcePolicy=knowledge_only cannot be combined with message attachments; upload them to Mind knowledge first`, invalid `response_format` / `tools` / `tool_choice` (see the schemas), `Unsupported provider: '{provider}'. Supported providers: openai, anthropic, google.`, `Cannot auto-detect provider for model '{model}'. Please specify a 'provider' parameter (openai, anthropic, or google).`, `Unsupported model '{model}' for provider '{provider}'. Supported models: …`. After generation started: `data.errorType: model_not_found` (the pinned model is unavailable), `invalid_prompt` (conversation too long or malformed), or `unsupported_model_capability` (`data.capability: tools | tool_choice`: the chosen model cannot call tools or honour a forced `tool_choice`; in stream mode the `error` frame carries `errorType`)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"`Access denied` when the Mind access rule is not met, `Upload access denied` for an unauthorized workspace attachment, or a plan limit: the monthly synthetic-response allowance is exhausted (`data.code: PLAN_LIMIT`, `limitType: responses`, `{Plan} plan monthly synthetic-response limit reached. Upgrade your plan for more responses.`, with `periodEnd` for the reset date). One response is reserved before generation and refunded if generation fails.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatPlanLimitError"}}}},"404":{"description":"No Mind with this ID (`Mind not found`)."},"409":{"description":"The Mind is not ready to chat (`data.code: SPARK_NOT_READY`): `This Mind is still being prepared` (`trainingStatus: queued|running`) or, for a Mind without a system prompt, `This Mind has no system prompt yet; regenerate its prompt before it can chat` (`trainingStatus: failed`). A failed training attempt is retried automatically and reports `queued`. Poll `GET /v1/minds/{mindId}/training` until `readyToChat` is true. Ephemeral demo Minds are exempt from this gate.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MindCompletionNotReadyError"}}}},"413":{"description":"Chat request exceeds the 1 MiB JSON limit. Returned before opening SSE or starting provider work."},"429":{"description":"Rate limit exceeded: at most 30 completions per user per sliding 60 s window (`Too many requests — please try again shortly.`). Every response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining`; a 429 adds `Retry-After` (seconds).","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until the window resets."},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}}}},"500":{"description":"Generation failed (`AI generation failed. Please try again in a moment.`, `data.errorType: ai_generation_error`). The reserved synthetic response is refunded."},"503":{"description":"Usage metering is temporarily unavailable (`data.code: USAGE_METERING_UNAVAILABLE`); nothing was generated or charged, retry later."}},"operationId":"createMindCompletion","summary":"Stateless completion with a Mind","description":"Send a conversation to a single Mind and get its next reply without any server-side state: you own the history and resend it every call. Omit `messages` (or send `[]`) to get the Mind's greeting. Supports OpenAI-style `response_format` (structured output), user-defined `tools` / `tool_choice` (function calling; calls are returned, never executed), file/link attachments via `messages[].metadata.attachedFiles`, a `model`/`provider` override, `language`, `sourcePolicy: \"knowledge_only\"` to retrieve processed Mind knowledge with internal web tools and request attachments disabled (persona fallback is reported when no evidence matches), and `citationMarkers` to control inline `[[CITE:n]]` markers. Default `responseMode: \"sync\"` returns buffered JSON; `responseMode: \"stream\"` returns Server-Sent Events (`start`, heartbeat comments, then a single `result` frame with the same payload, then `done`) to keep the connection active during long generations. JSON is limited to 1 MiB, 100 messages, 128 content parts per message and 100 total attachments; body admission returns HTTP 400/413 before opening a stream. Client disconnects cancel generation and structured extraction where the provider supports cancellation. Access rule: you can chat with Minds you own, Minds shared with you directly or with your team, Minds inside an Audience you own, belong to, or that is shared with your team, and public Minds; anything else returns 403 Access denied. The Mind must be trained (`readyToChat: true` on `GET /v1/minds/{mindId}/training`) or you get 409 `SPARK_NOT_READY`. Each call consumes one synthetic response from your monthly allowance and counts against the 30 completions/minute rate limit.","tags":["Chat"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MindCompletionRequest"},"examples":{"single":{"summary":"Single question","value":{"messages":[{"role":"user","content":"What are the top 3 marketing trends for 2026?"}]}},"greeting":{"summary":"Greeting bootstrap","value":{"messages":[]}},"multiTurn":{"summary":"Multi-turn with client-managed history","value":{"messages":[{"role":"user","content":"What are the top marketing trends?"},{"role":"assistant","content":"AI personalization, short-form video, and community building…"},{"role":"user","content":"How can I implement AI personalization on a budget?"}]}},"attachments":{"summary":"Attach a document","value":{"messages":[{"role":"user","content":"Summarize the key points of this report.","metadata":{"attachedFiles":[{"url":"https://example.com/quarterly-report.pdf","name":"Q4 Report","type":"application/pdf"}]}}]}},"knowledgeOnly":{"summary":"Knowledge-only, plain prose, streamed","value":{"responseMode":"stream","sourcePolicy":"knowledge_only","citationMarkers":"none","messages":[{"role":"user","content":"What does the study say about classroom smartphone rules?"}]}},"structured":{"summary":"Structured output","value":{"messages":[{"role":"user","content":"Analyze the sentiment of: I love this product, it exceeded all my expectations!"}],"response_format":{"type":"json_schema","json_schema":{"name":"sentiment_analysis","schema":{"type":"object","properties":{"sentiment":{"type":"string","enum":["positive","negative","neutral"]},"confidence":{"type":"number","minimum":0,"maximum":1}},"required":["sentiment","confidence"]}}}}},"tools":{"summary":"Function calling","value":{"messages":[{"role":"user","content":"What is the weather in Berlin?"}],"tools":[{"name":"get_weather","description":"Get current weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"},"units":{"type":"string","enum":["celsius","fahrenheit"]}},"required":["city"]}}],"tool_choice":"auto"}},"modelOverride":{"summary":"Pin a model","value":{"model":"gpt-6-luna","provider":"openai","language":"de","endUserName":"Lena","messages":[{"role":"user","content":"Was hältst du von nachhaltiger Verpackung?"}]}}}}}}}},"/api/v1/minds/{mindId}/export-download":{"get":{"responses":{"200":{"description":"The export file. `Content-Type` matches the artifact and `Content-Disposition` carries the filename.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}},"text/markdown":{"schema":{"type":"string"}},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"schema":{"type":"string","format":"binary"}},"application/vnd.openxmlformats-officedocument.presentationml.presentation":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"`Invalid Mind ID format` (not a UUID)."},"401":{"description":"`Unauthorized`: the Mind is private and no valid credential was supplied."},"403":{"description":"`Not authorized` (caller cannot read this private Mind) or `Exporting results requires a Starter plan or above` (neither the caller nor the Mind owner is on a paid plan; `data.code` is `PLAN_LIMIT`, `limitType` `exports`)."},"404":{"description":"`Mind not found`; `Export not found. Try regenerating it.` (the `jobId` is unknown, not yet completed, or does not match this Mind, format, and locale); or `No export available. Generate it first.` (no cached artifact for that format and locale)."},"500":{"description":"Internal server error (including a failed download from storage)."}},"operationId":"downloadMindExport","summary":"Download a Mind export","description":"Stream the bytes of a completed persona-profile export as a file attachment (`Content-Disposition: attachment`). Pass the `jobId` from `POST /v1/minds/{mindId}/export` (with the same `format` and `locale`) to fetch that job's artifact, or omit `jobId` to download the cached artifact for the given format and locale. Use `GET /v1/minds/{mindId}/export-status` first when you are not sure the export has finished. Public and link-shared Minds can be downloaded without authentication; private Minds require a caller who can read them (see the Minds access rule). Exports also require the caller or the Mind owner to be on an Individual plan or above.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"jobId","required":false,"description":"Completed export job ID. Omit to download the cached artifact for `format` / `locale`.","schema":{"type":"string"}},{"in":"query","name":"format","required":false,"description":"Export format to download. `markdown` is accepted as an alias for `md`; unknown values fall back to `md`.","schema":{"type":"string","enum":["pdf","md","docx","pptx"],"default":"md"}},{"in":"query","name":"locale","required":false,"description":"Locale of the export. Defaults to the authenticated user's locale; unsupported values are ignored.","schema":{"type":"string","enum":["en","es","fr","de","zh","tr","ar","ja","ko"]}}]}},"/api/v1/minds/{mindId}/export-status":{"get":{"responses":{"200":{"description":"Export status. Completed responses carry the artifact inline unless `metadata=1` was passed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MindExportStatusResponse"},"examples":{"processing":{"summary":"Job still running","value":{"data":{"status":"processing","progress":40}}},"completed":{"summary":"Markdown artifact ready","value":{"data":{"status":"completed","kind":"persona_profile","format":"md","filename":"Marketing Expert.md","mimeType":"text/markdown;charset=utf-8","generatedAt":"2025-12-10T12:00:00.000Z","downloadUrl":"/api/v1/minds/550e8400-e29b-41d4-a716-446655440000/export-download?format=md&locale=en&jobId=1234","content":"# Marketing Expert\n\n..."}}},"idle":{"summary":"Nothing generated yet","value":{"data":{"status":"idle"}}}}}}},"400":{"description":"`Invalid Mind ID format` (not a UUID)."},"401":{"description":"`Unauthorized`: the Mind is private and no valid credential was supplied."},"403":{"description":"`Not authorized` (caller cannot read this private Mind) or `Exporting results requires a Starter plan or above` (neither the caller nor the Mind owner is on a paid plan; `data.code` is `PLAN_LIMIT`, `limitType` `exports`)."},"404":{"description":"`Mind not found`."},"500":{"description":"Internal server error."}},"operationId":"getMindExportStatus","summary":"Get Mind export status","description":"Poll a persona-profile export started with `POST /v1/minds/{mindId}/export`. Pass the `jobId` from the queued response (together with the same `format` and `locale`) to follow that job: `queued` and `processing` carry a `progress` percentage, `failed` carries an `error`, and `completed` returns the artifact inline (`content` for md, `contentBase64` for pdf/docx/pptx) plus a `downloadUrl` for `GET /v1/minds/{mindId}/export-download`. Without `jobId` the endpoint reports the cached artifact for that format and locale (`completed`) or `idle` when nothing has been generated yet. Pass `metadata=1` (or `inline=0`) to omit the inline file bytes and receive only filename, MIME type, and download URL. Public and link-shared Minds can be polled without authentication; private Minds require a caller who can read them (see the Minds access rule). Exports also require the caller or the Mind owner to be on an Individual plan or above.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"jobId","required":false,"description":"Export job ID returned by `POST /v1/minds/{mindId}/export`. Omit to read the cached artifact / idle state instead.","schema":{"type":"string"}},{"in":"query","name":"format","required":false,"description":"Export format the job or cached artifact was generated in. `markdown` is accepted as an alias for `md`; unknown values fall back to `md`.","schema":{"type":"string","enum":["pdf","md","docx","pptx"],"default":"md"}},{"in":"query","name":"locale","required":false,"description":"Locale of the export. Defaults to the authenticated user's locale; unsupported values are ignored.","schema":{"type":"string","enum":["en","es","fr","de","zh","tr","ar","ja","ko"]}},{"in":"query","name":"metadata","required":false,"description":"Set to `1` or `true` to omit the inline `content` / `contentBase64` from a completed response.","schema":{"type":"string","enum":["1","true"]}},{"in":"query","name":"inline","required":false,"description":"Set to `0` or `false` to omit the inline `content` / `contentBase64` (same effect as `metadata=1`).","schema":{"type":"string","enum":["0","false"]}}]}},"/api/v1/minds/{mindId}/export":{"post":{"responses":{"200":{"description":"Cached artifact or queued job."},"400":{"description":"Invalid Mind ID or export format."},"401":{"description":"Authentication required for a private Mind."},"403":{"description":"Caller cannot access the Mind."},"404":{"description":"Mind does not exist."},"500":{"description":"Internal server error."}},"operationId":"exportMindPersona","summary":"Export a Mind persona profile","description":"Generate a branded persona profile for a single Mind, summarizing who they are, how they think and what they read. The heavy generation runs in the processor; the endpoint returns the artifact inline (`content` for md, `contentBase64` for pdf/docx/pptx) and serves a cached result instantly. Formats: pdf (portrait), md, docx, pptx.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"format":{"type":"string","enum":["pdf","md","docx","pptx"],"default":"md"},"force":{"type":"boolean","default":false,"description":"Regenerate even when a cached artifact exists."}}}}}}}},"/api/v1/minds/{mindId}/knowledge/{itemId}":{"delete":{"responses":{"204":{"description":"Item, patterns, embeddings, and stored file removed. Empty body."},"400":{"description":"Invalid path parameter: `Mind ID is required`, `Invalid Mind ID format`, `Knowledge item ID is required`, or `Invalid knowledge item ID format`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Mind not found or access denied` (Mind missing or caller lacks edit rights) or `Knowledge item not found` (item does not belong to this Mind)."},"500":{"description":"`Failed to delete knowledge item` (the item record could not be removed)."}},"operationId":"deleteMindKnowledgeItem","summary":"Delete a knowledge item","description":"Permanently remove a knowledge item from a Mind together with its thinking patterns, its retrieval embeddings, and (for uploads) the stored file. The item record is deleted last; if a dependent cleanup step fails it is logged and the deletion still succeeds, so a 204 means the item is gone from the Mind and will no longer be retrieved in chat. This cannot be undone. The Mind system prompt is not regenerated by this call. Access: you must be able to edit the Mind (owner, direct collaborator, or member of the team the Mind is shared with); other Minds answer 404 `Mind not found or access denied`.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}},{"in":"path","name":"itemId","required":true,"description":"Knowledge item UUID (from the list or add response).","schema":{"type":"string","format":"uuid"}}]},"put":{"responses":{"200":{"description":"Updated item. This response omits `processing` and `statusUrl`; fetch the list or status endpoint for those.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/KnowledgeItem"}}},"examples":{"updated":{"summary":"Renamed file item","value":{"success":true,"data":{"id":"660e8400-e29b-41d4-a716-446655440001","description":"Updated handbook description","link":null,"filePath":"portfolio/user-id/1234567890_handbook.pdf","isWatched":false,"createdAt":"2025-12-10T12:00:00.000Z","updatedAt":"2025-12-15T08:30:00.000Z"}}}}}}},"400":{"description":"Validation error: `Mind ID is required`, `Invalid Mind ID format`, `Knowledge item ID is required`, `Invalid knowledge item ID format`, `Description must not be empty`, or `No valid fields to update. Updatable fields: description`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Mind not found or access denied` (Mind missing or caller lacks edit rights) or `Knowledge item not found` (item does not belong to this Mind)."},"500":{"description":"`Failed to update knowledge item`."}},"operationId":"updateMindKnowledgeItem","summary":"Update a knowledge item","description":"Rename the `description` of an existing knowledge item. `description` is the only updatable field: a body without a string `description` is rejected with 400 `No valid fields to update. Updatable fields: description`, and a blank/whitespace-only value is rejected with 400 `Description must not be empty`. The value is trimmed before saving. Changing the description does not re-run ingestion; use `DELETE` + `POST` to replace the underlying content. Access: you must be able to edit the Mind (owner, direct collaborator, or member of the team the Mind is shared with); other Minds answer 404 `Mind not found or access denied`.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}},{"in":"path","name":"itemId","required":true,"description":"Knowledge item UUID (from the list or add response).","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["description"],"properties":{"description":{"type":"string","minLength":1,"description":"New description. Trimmed; must not be empty."}}},"examples":{"rename":{"summary":"Rename an item","value":{"description":"Updated handbook description"}}}}}}}},"/api/v1/minds/{mindId}/knowledge/{itemId}/status":{"get":{"responses":{"200":{"description":"Processing state, embedding/pattern counts, and readyForRetrieval."},"400":{"description":"Invalid Mind or knowledge item ID."},"401":{"description":"Missing or invalid API key."},"404":{"description":"Mind or knowledge item not found or access denied."},"500":{"description":"Internal server error."}},"operationId":"getMindKnowledgeItemStatus","summary":"Get knowledge ingestion status","description":"Returns public processing fields and retrieval readiness for one Mind knowledge item. Worker diagnostics are omitted; failures use a generic message. Responses are private and not cached.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"itemId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds/{mindId}/knowledge/enrich":{"post":{"responses":{"202":{"description":"Enrichment queued (identical to the keyword-mode response of `addMindKnowledge`).","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"$ref":"#/components/schemas/KnowledgeEnrichmentAccepted"}}}}}},"400":{"description":"Validation error, in check order: `Mind ID is required`, `Invalid Mind ID format`, `keywords array is required and must not be empty` (missing/empty array or non-JSON body), then from the forwarded handler `At least one valid keyword is required` (every entry blank or non-string)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Mind not found or access denied`: the Mind does not exist or the caller lacks edit rights."},"500":{"description":"Internal server error."}},"operationId":"enrichMindKnowledge","summary":"Enrich a Mind from keyword web search (alias)","description":"Convenience alias for the keyword-search mode of `POST /v1/minds/{mindId}/knowledge` (`addMindKnowledge`): it validates that `keywords` is a non-empty array and then forwards the same request to that endpoint, so behaviour, limits, and the 202 response are identical. Use it when you want an endpoint that only accepts keyword enrichment; use the main endpoint if you also add links or files. Send `Content-Type: application/json` with `keywords` (and optionally `regeneratePrompt`, default `true`) and nothing else: because the request is forwarded verbatim, a body that also contains `file` is treated as a remote-file upload by the target handler. Keywords are trimmed, de-duplicated, and capped at 15 (extra keywords are silently dropped). The search runs in the background; poll `GET /v1/minds/{mindId}/training` for progress. Access: you must be able to edit the Mind (owner, direct collaborator, or member of the team the Mind is shared with); other Minds answer 404 `Mind not found or access denied`.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddKnowledgeKeywordsRequest"},"examples":{"keywords":{"summary":"Two search topics","value":{"keywords":["solar study efficiency","photovoltaic trends"]}},"noPromptRegeneration":{"summary":"Keep the current system prompt","value":{"keywords":["battery storage economics"],"regeneratePrompt":false}}}}}}}},"/api/v1/minds/{mindId}/knowledge":{"get":{"responses":{"200":{"description":"Knowledge items ordered by `createdAt` descending.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["items","total","pagination"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeItem"}},"total":{"type":"integer","description":"Total number of items attached to this Mind, including other pages."},"pagination":{"type":"object","required":["limit","offset","hasMore"],"properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0},"hasMore":{"type":"boolean"}}}}}}},"examples":{"list":{"summary":"One file item and one link item","value":{"success":true,"data":{"items":[{"id":"660e8400-e29b-41d4-a716-446655440001","description":"Company Employee Handbook 2025","link":null,"filePath":"portfolio/user-id/1234567890_handbook.pdf","isWatched":false,"category":"employment","relevance":0.82,"evidence":"reference","processing":{"status":"completed","regeneratePrompt":false},"statusUrl":"/api/v1/minds/550e8400-e29b-41d4-a716-446655440000/knowledge/660e8400-e29b-41d4-a716-446655440001/status","createdAt":"2025-12-10T12:00:00.000Z","updatedAt":"2025-12-10T12:05:00.000Z"},{"id":"660e8400-e29b-41d4-a716-446655440002","description":"Industry trends article","link":"https://example.com/article","filePath":null,"isWatched":true,"category":"uncategorized","relevance":null,"evidence":null,"processing":{"status":"queued","regeneratePrompt":false},"statusUrl":"/api/v1/minds/550e8400-e29b-41d4-a716-446655440000/knowledge/660e8400-e29b-41d4-a716-446655440002/status","createdAt":"2025-12-09T12:00:00.000Z","updatedAt":"2025-12-09T12:00:00.000Z"}],"total":2,"pagination":{"limit":100,"offset":0,"hasMore":false}}}}}}}},"400":{"description":"Invalid pagination or Mind ID: `Mind ID is required` or `Invalid Mind ID format` (not a UUID)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"404":{"description":"`Mind not found or access denied`: the Mind does not exist or the caller is not its owner, a direct collaborator, or a member of the team it is shared with."},"500":{"description":"Internal server error."}},"operationId":"listMindKnowledge","summary":"List knowledge items of a Mind","description":"Return a page of knowledge items (uploaded files, links, or auto-collected sources) attached to a Mind, newest first with ID as a stable tie-breaker. Use limit (default and maximum 100) and offset (default 0). data.total counts all items; data.pagination.hasMore indicates continuation. Each item carries its knowledge `category` (the goal it was collected for, else a one-time reading of its content), its `relevance` (the content review's 0–1 score for the role or search topic it was reviewed for, shared across Minds) and its `evidence` type (both null until the source has been reviewed), its durable background `processing` state (absent for legacy items ingested before processing metadata was recorded) and a `statusUrl` you can poll for embedding/pattern counts and `readyForRetrieval`. Use it after adding knowledge to find item IDs for `PUT`/`DELETE`, or to audit what a Mind was trained on. Access: you must be able to edit the Mind (owner, direct collaborator, or member of the team the Mind is shared with); any other Mind, including public ones, answers 404 `Mind not found or access denied`.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"default":0}}]},"post":{"responses":{"202":{"description":"Accepted for background processing. File and link modes return the created item (`KnowledgeItemAccepted`); keyword mode returns the queued enrichment job (`KnowledgeEnrichmentAccepted`).","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","oneOf":[{"$ref":"#/components/schemas/KnowledgeItemAccepted"},{"$ref":"#/components/schemas/KnowledgeEnrichmentAccepted"}]}}},"examples":{"file":{"summary":"File accepted","value":{"success":true,"data":{"id":"660e8400-e29b-41d4-a716-446655440001","filePath":"portfolio/user-id/1234567890_handbook.pdf","description":"Company Employee Handbook 2025","createdAt":"2025-12-10T12:00:00.000Z","processing":{"status":"queued","regeneratePrompt":false},"statusUrl":"/api/v1/minds/550e8400-e29b-41d4-a716-446655440000/knowledge/660e8400-e29b-41d4-a716-446655440001/status"}}},"link":{"summary":"Link accepted","value":{"success":true,"data":{"id":"660e8400-e29b-41d4-a716-446655440002","link":"https://example.com/article","description":"Industry trends article","createdAt":"2025-12-10T12:00:00.000Z","processing":{"status":"queued","regeneratePrompt":false},"statusUrl":"/api/v1/minds/550e8400-e29b-41d4-a716-446655440000/knowledge/660e8400-e29b-41d4-a716-446655440002/status"}}},"keywords":{"summary":"Enrichment queued","value":{"success":true,"data":{"mindId":"550e8400-e29b-41d4-a716-446655440000","keywords":["solar study efficiency","photovoltaic trends"],"queued":true,"regeneratePrompt":true,"message":"Knowledge enrichment queued with 2 keyword(s). Web search and content processing will run in background."}}}}}}},"400":{"description":"Validation error. Path: `Mind ID is required`, `Invalid Mind ID format`. Multipart: `No form data provided`, `Description is required`, `No file provided`, `File too large: {name} ({size}MB). Maximum size is 50MB.`. Remote file: `file.name, file.url, and description are required`, `File URL is not a safe or fetchable public/workspace upload URL`, `Could not fetch file URL (HTTP {status})`, `File exceeds the 50MB knowledge upload limit`. Keywords: `Keywords array must not be empty`, `At least one valid keyword is required`. Link: `Link and description are required (or provide keywords array for web search)`, or the SDK-shape hint `Use { link, description } not { type: 'link', url }. …` when the body carries `url` instead of `link`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"`Upload access denied`: a workspace upload requires ownership, a valid signed chat-file capability, or access through the uploader-owned Study that shares the context file. Mind-edit access alone does not grant access to another user’s uploads."},"404":{"description":"`Mind not found or access denied`: the Mind does not exist or the caller is not its owner, a direct collaborator, or a member of the team it is shared with."},"413":{"description":"Request exceeds the bounded JSON/multipart limit, or the uploaded file is empty or too large."},"415":{"description":"`Unsupported Content-Type. Use application/json for links or multipart/form-data for files`."},"500":{"description":"Database failure: `Failed to create portfolio item`, or `Internal server error`."},"502":{"description":"The bounded storage upload failed or returned an invalid receipt."}},"operationId":"addMindKnowledge","summary":"Add knowledge to a Mind","description":"Attach new knowledge to a Mind. Pick the input by content type and body shape: (1) `multipart/form-data` with a `file` part uploads a document or image (max 50 MB); (2) JSON `{ file: { name, url, type? }, description }` ingests a file the server fetches itself from a public URL or a Minds workspace upload URL (SSRF-protected, 20 s fetch timeout, same 50 MB limit); (3) JSON `{ link, description }` ingests a web page, YouTube video, or paper URL; (4) JSON `{ keywords: [...] }` runs a web search per keyword and adds what it finds. JSON bodies are dispatched in the order `file`, then `keywords`, then link, so send exactly one shape. Modes 1-3 create one knowledge item, return it with `processing.status: queued` and a `statusUrl`. For files, the text is indexed before the response when it can be read directly (`searchable: true`), so the Mind can use the file at once; tables and charts are added in the background. Otherwise poll that URL (or `GET .../knowledge/{itemId}/status`) until `readyForRetrieval` is true before relying on the content, especially with `sourcePolicy: knowledge_only`. Mode 4 queues a Mind-level enrichment job instead (no item is returned; keywords are trimmed, de-duplicated, and capped at 15); track it via `GET /v1/minds/{mindId}/training`. `regeneratePrompt` (rebuild the system prompt after ingestion succeeds) defaults to `false` for files and links and `true` for keywords. Access: you must be able to edit the Mind (owner, direct collaborator, or member of the team the Mind is shared with); other Minds answer 404 `Mind not found or access denied`.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","oneOf":[{"$ref":"#/components/schemas/AddKnowledgeLinkRequest"},{"$ref":"#/components/schemas/AddKnowledgeRemoteFileRequest"},{"$ref":"#/components/schemas/AddKnowledgeKeywordsRequest"}]},"examples":{"link":{"summary":"Add a URL","value":{"link":"https://example.com/article","description":"Industry trends article"}},"remoteFile":{"summary":"Ingest a file from a signed URL","value":{"file":{"name":"handbook.pdf","url":"https://files.example.com/signed/handbook.pdf","type":"application/pdf"},"description":"Company Employee Handbook 2025","regeneratePrompt":false}},"keywords":{"summary":"Enrich via keyword web search","value":{"keywords":["solar study efficiency","photovoltaic trends"],"regeneratePrompt":true}}}},"multipart/form-data":{"schema":{"type":"object","required":["file","description"],"properties":{"file":{"type":"string","format":"binary","description":"Document (PDF, DOCX, DOC, TXT, MD, RTF, CSV, JSON, XML) or image (JPG, JPEG, PNG, GIF, WEBP). Max 50 MB. The part must carry a filename."},"description":{"type":"string","description":"Description of the content. Required; whitespace-only is rejected."},"regeneratePrompt":{"type":"string","enum":["true","false"],"default":"false","description":"Send the literal string `true` to regenerate the Mind system prompt after ingestion succeeds; any other value means false."}}},"encoding":{"file":{"contentType":"application/pdf, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/msword, text/plain, text/markdown, text/rtf, text/csv, application/json, application/xml, image/jpeg, image/png, image/gif, image/webp"}}}}}}},"/api/v1/minds/{mindId}/knowledge/patterns":{"get":{"responses":{"200":{"description":"Patterns grouped by framework. `frameworks` is empty when no patterns have been extracted yet.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","const":true},"data":{"type":"object","required":["mindId","mindName","totalPatterns","frameworks"],"properties":{"mindId":{"type":"string","format":"uuid"},"mindName":{"type":"string"},"totalPatterns":{"type":"integer","description":"Total stored patterns for the Mind, including any whose aspect matches no framework."},"frameworks":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgePatternFramework"}}}}}},"examples":{"privileged":{"summary":"Owner view with provenance","value":{"success":true,"data":{"mindId":"550e8400-e29b-41d4-a716-446655440000","mindName":"Marketing Expert","totalPatterns":3,"frameworks":[{"id":"ocean","name":"Big Five (OCEAN)","totalOccurrences":3,"aspects":[{"id":"ocean-O","name":"Openness to Experience","description":"Imagination, curiosity, and openness to new ideas.","occurrences":3,"subAspects":[{"id":"ocean-O-1","name":"Fantasy","description":"Rich imaginative life.","occurrences":2,"evidence":[{"mind":"Prefers bold campaign concepts over incremental tweaks.","portfolioItemId":"660e8400-e29b-41d4-a716-446655440001","createdAt":"2025-12-10T12:05:00.000Z"}]},{"id":"(none)","name":"(General)","description":"","occurrences":1,"evidence":[{"mind":"Explores adjacent markets before committing budget.","portfolioItemId":null,"createdAt":"2025-12-10T12:05:00.000Z"}]}]}]}]}}}}}}},"400":{"description":"Invalid Mind ID: `Mind ID is required` or `Invalid Mind ID format` (not a UUID)."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"`Access denied to this Mind`: the Mind is not public and the caller is not its owner, a direct collaborator, a member of the team it is shared with, or a member of a private Audience containing it."},"404":{"description":"`Mind not found`."},"500":{"description":"Internal server error."}},"operationId":"getMindKnowledgePatterns","summary":"Get thinking patterns grouped by framework","description":"Return the thinking patterns extracted from a Mind's knowledge, grouped by psychological/behavioural framework (for example Big Five, DISC, Holland Codes), then by aspect and sub-aspect, each with occurrence counts and the supporting evidence quotes. Frameworks, aspects, and sub-aspects with zero occurrences are omitted, and every level is sorted by occurrences descending. Use it to explain *why* a Mind answers the way it does, to audit training coverage, or to build profile visualisations. Access: the Mind's owner, direct collaborators, members of the team it is shared with, and members of a private Audience containing it (Audience owner, Audience member, or member of the team the Audience is shared with) see full evidence including `portfolioItemId` and `createdAt`; anyone else may read only public Minds and receives evidence quotes without those provenance fields. Any other Mind answers 403 `Access denied to this Mind`.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds/{mindId}/patterns":{"get":{"responses":{"200":{"description":"Pattern rows ordered by `createdAt` descending.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MindPattern"}}}},"example":{"data":[{"id":12345,"mindId":"550e8400-e29b-41d4-a716-446655440000","userId":"8f3e1c2a-1b2c-4d5e-9f00-1234567890ab","messageId":null,"portfolioItemId":"0b1c2d3e-4f50-4617-8899-aabbccddeeff","aspect":"Strategic Thinking","subAspect":"Market Analysis","mind":"Market segmentation requires understanding customer pain points...","isPredefined":true,"isPredefinedAspect":true,"isPredefinedSubAspect":true,"createdAt":"2025-12-10T15:30:00.000Z"}]}}}},"400":{"description":"`Invalid Mind ID format` (not a UUID)."},"401":{"description":"`Unauthorized`: the Mind is private and no valid credential was supplied."},"403":{"description":"`Access denied`: caller cannot read this private Mind."},"404":{"description":"`Mind not found`."},"500":{"description":"Internal server error."}},"operationId":"listMindPatterns","summary":"List raw Mind patterns","description":"Return the raw pattern rows extracted from a Mind's knowledge, newest first: one row per detected aspect / sub-aspect pair with the supporting `mind` quote. This is the unaggregated feed behind the SphereGraph visualisation; use `GET /v1/minds/{mindId}/knowledge/patterns` for the framework-grouped view. Public and link-shared Minds can be read without authentication. Otherwise the caller must be able to read the Mind: readable Minds are those you own, Minds shared with you directly or with your team, Minds inside an Audience you own, belong to, or that is shared with your team, Minds inside a Study you belong to, and public Minds; anything else returns 403 `Access denied`. Owners, direct members, shared-team members, and private-Audience viewers receive the full rows (`userId`, `portfolioItemId`, `messageId`, predefined flags, `createdAt`); every other reader receives only `id`, `aspect`, `subAspect`, and `mind`.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds/{mindId}/regenerate-embeddings":{"post":{"responses":{"202":{"description":"Embedding rebuild jobs queued."},"400":{"description":"Invalid Mind ID format (not a UUID)."},"401":{"description":"Missing or invalid API key."},"404":{"description":"Mind does not exist or is not accessible."},"503":{"description":"The rebuild could not be queued."}},"operationId":"regenerateMindEmbeddings","summary":"Regenerate a mind knowledge index","description":"Queues a fresh embedding rebuild for every knowledge item using the current content-maintenance processor. This does not revive or publish to the retired `regenerate-embeddings` queue.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds/{mindId}/regenerate-image":{"post":{"responses":{"200":{"description":"Job enqueued, or skipped because an image already exists.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["mindId","name","enqueued"],"properties":{"mindId":{"type":"string","format":"uuid"},"name":{"type":"string"},"enqueued":{"type":"boolean","description":"True when a generation job was queued."},"skippedReason":{"type":"string","description":"Present when `enqueued` is false, e.g. `image already set (pass force=true to regenerate)`."}}}}},"examples":{"enqueued":{"summary":"Job queued","value":{"success":true,"data":{"mindId":"550e8400-e29b-41d4-a716-446655440000","name":"My Mind","enqueued":true}}},"skipped":{"summary":"Image already present","value":{"success":true,"data":{"mindId":"550e8400-e29b-41d4-a716-446655440000","name":"My Mind","enqueued":false,"skippedReason":"image already set (pass force=true to regenerate)"}}}}}}},"400":{"description":"`Invalid Mind ID format` (not a UUID) or `personaContext exceeds 16000 characters`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"`Forbidden`: caller is neither the owner nor an admin member of this Mind."},"404":{"description":"`Mind not found`."},"500":{"description":"Internal server error."},"503":{"description":"Image generation could not be queued; retryable."}},"operationId":"regenerateMindImage","summary":"Regenerate a Mind's profile image","description":"Queue AI generation of a new profile image for a Mind. The request returns as soon as the job is enqueued; poll `GET /v1/minds/{mindId}` until `profileImageUrl` is set or changes. The job is idempotent: when the Mind already has an image the endpoint returns `enqueued: false` with a `skippedReason` unless `force: true`, in which case the current image stays visible until a fresh portrait generated from the Mind's name, discipline, and system prompt replaces it. Pass `personaContext` to steer the image prompt without altering the stored system prompt. Callable by the owner or by a direct Mind member with the `admin` role; everyone else gets 403 `Forbidden`.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"force":{"type":"boolean","default":false,"description":"Regenerate even when a profile image is already set."},"personaContext":{"type":"string","maxLength":16000,"description":"Optional persona description fed to the image-prompt generator instead of the default \"name — discipline\". Trimmed; blank values are ignored."}}},"examples":{"fill":{"summary":"Generate only if missing (empty body is also accepted)","value":{}},"force":{"summary":"Replace the current image","value":{"force":true,"personaContext":"A senior plumber in her fifties, workshop background, warm natural light"}}}}}}}},"/api/v1/minds/{mindId}/regenerate-prompt":{"post":{"responses":{"200":{"description":"The regenerated prompt has been saved on the Mind.","content":{"application/json":{"schema":{"type":"object","required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","required":["id","name","systemPrompt","promptLength"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"systemPrompt":{"type":"string","description":"The new system prompt as persisted."},"promptLength":{"type":"integer","description":"Character length of `systemPrompt`."}}}}},"example":{"success":true,"data":{"id":"550e8400-e29b-41d4-a716-446655440000","name":"My Mind","systemPrompt":"## Life Story & Background\n\n...","promptLength":2847}}}}},"400":{"description":"`Invalid Mind ID format` (not a UUID) or `personaContextOverride exceeds 16000 characters`."},"401":{"description":"Missing or invalid API key (`Unauthorized`)."},"403":{"description":"`Forbidden`: caller does not own this Mind."},"404":{"description":"`Mind not found`."},"500":{"description":"`Failed to generate system prompt - insufficient content generated` (the knowledge base produced fewer than 50 characters) or `Failed to generate system prompt` (generation error)."}},"operationId":"regenerateMindPrompt","summary":"Regenerate a Mind's system prompt","description":"Rebuild the Mind's full system prompt from its current knowledge base (knowledge items, patterns, embeddings), replacing any manual edits. Runs synchronously and returns the new prompt; the same generator powers the product's \"Generate All\" action. Call it after adding knowledge with the Knowledge API, or to reset a customised prompt. The optional `personaContextOverride` is injected as a highest-priority steering brief (for example to diverge from a sibling persona or adjust age / family details) without touching the stored knowledge; context from the caller's own Audiences and the Mind's cohort profile is added automatically. A Mind allocated into an Audience keeps its assigned identity: its exact age, gender and race/ethnicity are supplied to the generator and enforced on the result (demographic header and the biography's own stated age), so neither the override nor the generator can change them. Only the Mind owner may call this; members and team collaborators get 403 `Forbidden`.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"personaContextOverride":{"type":"string","maxLength":16000,"description":"Free-form brief injected into the generator as a source-of-truth constraint. Trimmed; blank values are ignored."}}},"examples":{"plain":{"summary":"Regenerate from knowledge only (empty body is also accepted)","value":{}},"steering":{"summary":"Steer the regeneration","value":{"personaContextOverride":"She is 42, lives in Leipzig with two teenage children, and is sceptical of subscription pricing."}}}}}}}},"/api/v1/minds/{mindId}/retrain":{"post":{"responses":{"200":{"description":"Retrain queued, or the retrain already in flight.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingStatus"}}}},"202":{"description":"A Study run is answering with this mind: the retrain is recorded and starts once that run has finished. The training block is the current one, plus `retrainAfterRuns: { studyIds }`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingStatus"}}}},"400":{"description":"Invalid Mind ID format (not a UUID)."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller does not own this Mind."},"404":{"description":"Mind does not exist."},"500":{"description":"Internal server error."},"503":{"description":"Another claim kept changing the mind while the retrain was being started (`data.code: MIND_RETRAIN_CONTENDED`, `retryable: true`). Nothing was started; ask again."}},"operationId":"retrainMind","summary":"Retrain a mind","description":"Re-run training for a mind. Failed accepted training preserves its verified original sources, settings and worker phase; when that request cannot be verified the mind is rebuilt from its current profile, and its instructions are rewritten from that profile. Ordinary rebuilds regenerate stored knowledge embeddings. The response is the training block — poll GET /v1/minds/{id}/training until `readyToChat` is true. The call never refuses a retrain: if one is already `queued` or `running`, that attempt is returned (200); if a Study run is answering with the mind, the retrain is recorded and starts automatically once the run has finished (202, `retrainAfterRuns.studyIds`).","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds/{mindId}/training":{"get":{"responses":{"200":{"description":"Training status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingStatus"}}}},"400":{"description":"Invalid Mind ID format (not a UUID)."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller does not have access to this Mind."},"404":{"description":"Mind does not exist."},"500":{"description":"Internal server error."}},"operationId":"getMindTrainingStatus","summary":"Poll a mind's training status","description":"Returns the live training lifecycle for a mind. A mind's `id` exists the instant it is created, but it is only usable once `readyToChat` is `true`. Poll this endpoint after creating a mind in an auto mode (`keywords`, `clone`, `link`) until `readyToChat` flips true. The mind keeps learning from its sources in the background after that (`learningInBackground`, then `fullyTrained`); there is no need to wait for it. A Mind without a system prompt is never ready: it reports `failed` with `error: { code: 'PROFILE_GEN_FAILED', retryable: true }` (this covers `manual`-mode minds until their prompt is regenerated, and any Mind whose training ended without a prompt). Minds created before 2026-09-18T21:30:00Z keep their historical readiness. Statuses are `queued`, `running`, `completed`, `failed` (there is no `idle`). `readyToChat` reports that the mind can answer, NOT that it has researched evidence: read `knowledgeState.fallbackOnly` to tell a mind trained on collected sources apart from one answering from its generated profile alone. On `failed`, `error.retryable` indicates whether `POST /v1/minds/{id}/retrain` is worth calling.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"mindId","required":true,"description":"Mind UUID.","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/minds":{"delete":{"responses":{"200":{"description":"Per-Mind deletion results."},"400":{"description":"Invalid or empty mindIds array."},"401":{"description":"Unauthorized."}},"operationId":"deleteMinds","summary":"Batch-delete owned Minds","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[]},"get":{"responses":{"200":{"description":"A page of minds.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/MindSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid `limit` or `offset`."},"401":{"description":"Missing or invalid API key."},"500":{"description":"Internal server error."}},"operationId":"listMinds","summary":"List Minds","description":"List the Minds the authenticated user can open, newest first: Minds they own and Minds shared with them directly, with their team, or through an Audience or Study they own or can open (the same rule as GET /api/v1/minds/library). `isOwner` tells owned and shared Minds apart. Supports text search by name/description/discipline and offset-based pagination. Ephemeral Minds created during in-product chats are excluded.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"search","description":"Case-insensitive substring match against name, description, and discipline.","required":false,"schema":{"type":"string"}},{"in":"query","name":"searchQuery","description":"Alias of `search`, matching the `list_minds` MCP tool. Sent together with `search`, both must be equal.","required":false,"schema":{"type":"string"}},{"in":"query","name":"limit","description":"Max minds per page.","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"in":"query","name":"offset","description":"Number of minds to skip.","required":false,"schema":{"type":"integer","minimum":0,"default":0}}]},"post":{"responses":{"201":{"description":"Mind created. The `training` block carries the initial lifecycle state: `queued` for auto modes; for `manual`, not ready (`failed`, retryable) until a system prompt is generated via regenerate-prompt.","content":{"application/json":{"schema":{"type":"object","required":["data","training"],"properties":{"data":{"allOf":[{"$ref":"#/components/schemas/MindSummary"},{"type":"object","required":["profileDetails"],"properties":{"profileDetails":{"$ref":"#/components/schemas/MindProfileDetails"}}}]},"training":{"$ref":"#/components/schemas/TrainingStatus"}}}}}},"400":{"description":"Validation error (missing `name`/`discipline`, invalid mode, mode-specific field missing, etc.)."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Plan limit reached (`code: PLAN_LIMIT`) or workspace creation is disabled."},"404":{"description":"The retry key refers to a Mind outside the current managed workspace."},"500":{"description":"Internal server error."}},"operationId":"createMind","summary":"Create a Mind","description":"Create a new AI Mind. Choose a training `mode`: `keywords` (default) seeds from keyword topics, `clone` emulates a named person/profile, `link` scrapes a URL, `manual` skips automatic data collection. The returned `training` block reflects the Mind's lifecycle: auto-processing modes start `queued` (poll `GET /v1/minds/{id}/training` until `readyToChat` is true), while `manual` Minds skip collection and have no system prompt yet, so they report `failed` (`PROFILE_GEN_FAILED`, retryable, `readyToChat: false`) until you add knowledge and call `POST /v1/minds/{id}/regenerate-prompt`; a Mind without a system prompt is never ready. A Mind's `id` exists before it is ready; do not chat until `readyToChat` is true.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"X-Minds-Idempotency-Key","in":"header","required":false,"schema":{"type":"string","minLength":1,"maxLength":128},"description":"Stable key for one creation operation, scoped to the authenticated owner. Reuse it with the same payload after a timeout; while the original Mind exists and remains accessible in the current workspace, the key returns that Mind with HTTP 200. Use a fresh key to create another Mind."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMindRequest"},"examples":{"keywords":{"summary":"Train from keywords","value":{"name":"Marketing Expert","description":"B2B SaaS marketing director","mode":"keywords","type":"expert","discipline":"Marketing","keywords":["B2B marketing","SaaS","growth marketing"],"tags":["marketing","b2b"]}},"clone":{"summary":"Clone a persona","value":{"name":"Ada Lovelace AI","description":"AI trained to emulate Ada Lovelace","mode":"clone","type":"expert","discipline":"Computer Science","personaContext":"Ada Lovelace, pioneering computer scientist"}},"link":{"summary":"Train from URL","value":{"name":"Brand Voice Expert","mode":"link","type":"creative","discipline":"Brand Strategy","contextLink":"https://example.com/brand-guidelines"}}}}}}}},"/api/v1/minds/library":{"get":{"responses":{"200":{"description":"The caller projection. Paged mode returns data plus pageInfo.nextCursor; null means the last page."},"401":{"description":"Missing or invalid authentication."}},"operationId":"listMindLibrary","summary":"List the first-party Mind library projection","description":"Returns every Mind the caller can open, with the caller effective role: owned Minds, public Minds, Minds shared directly or with the caller team, and every Mind in an Audience the caller owns, belongs to or that is shared with their team, or in a Study they can open. The paged modes and the unpaged projection apply the same rule. Private configuration fields are omitted when the caller has no member role.","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"mode","description":"Opt into bounded pages; omitted preserves the legacy projection.","schema":{"type":"string","enum":["sidebar","search","lookup","audience"]}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":60}},{"in":"query","name":"after","description":"Opaque nextCursor from the previous page with the same search and sort.","schema":{"type":"string"}},{"in":"query","name":"sort","schema":{"type":"string","enum":["name","createdAt","updatedAt"],"default":"updatedAt"}},{"in":"query","name":"direction","schema":{"type":"string","enum":["asc","desc"],"default":"desc"}},{"in":"query","name":"search","description":"Search all visible records, including unloaded pages.","schema":{"type":"string","maxLength":200}},{"in":"query","name":"ids","description":"Comma-separated UUIDs; at most 100.","schema":{"type":"string"}},{"in":"query","name":"audienceId","description":"Required with mode=audience; access is checked before loading members.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"category","schema":{"type":"string","enum":["all","personal","shared","public"]}},{"in":"query","name":"fresh","required":false,"description":"Set to 1 after an access change to bypass the short-lived library cache.","schema":{"type":"string","enum":["1"]}}]}},"/api/v1/minds/shared/{shareId}/knowledge":{"get":{"responses":{"200":{"description":"Public references and sphere categories, including source IDs that join patterns to items.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["patterns","items"],"properties":{"patterns":{"type":"array","items":{"type":"object"},"description":"Knowledge categories and stored source assessments; no source text."},"items":{"type":"array","items":{"type":"object","required":["id","description","link","createdAt","isAutoCollected","tags","metadata"],"properties":{"id":{"type":"string"},"description":{"type":"string","description":"Recorded public title, or hostname."},"link":{"type":"string","format":"uri"},"createdAt":{"type":"string","format":"date-time"},"isAutoCollected":{"type":"boolean","const":true},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","properties":{"title":{"type":"string"},"isSocialProfile":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false}}}}}}}}},"400":{"description":"Invalid share UUID."},"401":{"description":"Authentication required."},"404":{"description":"Mind not found or not publicly shared."},"500":{"description":"Could not load shared Mind sources."}},"operationId":"getSharedMindKnowledge","summary":"Read the public sources of a shared Mind","description":"Read the same collected public web references and knowledge-sphere categories shown at /minds/shared/{shareId}. Supply the share UUID from that URL, not the Mind ID. The share must still be public or link-enabled. API authentication is required, but Mind edit access is not. Returns all eligible references after deduplication. Uploaded files, owner-provided Audience corpora, connector records, source bodies and private metadata are excluded. Reading never starts collection or model work. Missing or revoked shares return 404.","tags":["Knowledge"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"shareId","required":true,"schema":{"type":"string","format":"uuid"},"description":"UUID from the shared Mind URL."}]}},"/api/v1/model-connections":{"get":{"responses":{"200":{"description":"Connection metadata, capability flags, and pagination.nextCursor. No credentials or raw probe results."},"400":{"description":"Invalid cursor."},"401":{"description":"Unauthorized."},"403":{"description":"Eligible team membership required."},"404":{"description":"Model connections disabled."},"500":{"description":"Internal server error."}},"operationId":"listModelConnections","summary":"List the caller team’s model connections and verified capabilities","tags":["Models"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/openapi.json":{"get":{"responses":{"200":{"description":"OpenAPI 3.1.0 document.","content":{"application/json":{"schema":{"type":"object"}}}}},"operationId":"getOpenApiDocument","summary":"Get the OpenAPI document","description":"Return this OpenAPI 3.1.0 document. Identical to `/_openapi.json`. No authentication required — the document describes how to authenticate.","tags":["Meta"],"security":[],"parameters":[]}},"/api/v1/research-methods":{"get":{"responses":{"200":{"description":"Versioned research methods.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object"}}}}}}},"401":{"description":"Missing or invalid authentication."}},"operationId":"listResearchMethods","summary":"List research methods","description":"Return the versioned research-method catalog, explicit executable state, availability, configuration JSON Schemas, semantic output types, fallback methods, and preparesQuestionsAtExecution (whether method configuration generates the execution questions). Experimental and planned methods are visible for framework compatibility but cannot be executed.","tags":["Research"],"security":[{"ApiKeyAuth":[]}],"parameters":[]}},"/api/v1/runs/{runId}/cancel":{"post":{"responses":{"200":{"description":"Cancellation state."},"404":{"description":"Run not found."}},"operationId":"cancelAgentRun","summary":"Cancel a durable run","tags":["Agent Runs"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"runId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/runs/{runId}/events":{"get":{"responses":{"200":{"description":"Events ordered by monotonically increasing sequence."}},"operationId":"listAgentRunEvents","summary":"Replay ordered durable run events","tags":["Agent Runs"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"runId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"after","required":false,"schema":{"type":"integer","minimum":-1,"default":-1}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}]}},"/api/v1/runs/{runId}":{"get":{"responses":{"200":{"description":"Authoritative run status. `readinessWait` (`waitingFor`, `notReadyCount`, `waitingSince`, `budgetMs`, `updatedAt`) is present while the run is queued waiting for Minds to finish training, and null otherwise. `budgetMs` is the alert threshold, not a deadline: the run keeps waiting for as long as the Minds are being trained. `error.code: minds_not_ready` is reported only for a run in which no Mind can answer and none can be retrained, naming them."},"404":{"description":"Run not found."}},"operationId":"getAgentRun","summary":"Get durable run status","tags":["Agent Runs"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"runId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/studies/{studyId}":{"delete":{"responses":{"204":{"description":"Study deleted."},"400":{"description":"Invalid study ID, or the Study is not in study mode."},"401":{"description":"Missing or invalid authentication."},"403":{"description":"Only the study owner may delete it."},"404":{"description":"Study not found."}},"operationId":"deleteStudy","summary":"Delete a study","description":"Delete a Study owned by the authenticated user.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}]},"get":{"responses":{"200":{"description":"Study details.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyDetail"}}}}}},"400":{"description":"Invalid study ID, or the Study is not in study mode."},"401":{"description":"Missing or invalid authentication."},"403":{"description":"The caller cannot access this study."},"404":{"description":"Study not found."}},"operationId":"getStudy","summary":"Get a study","description":"Return a Study with its attached audiences, Minds, and messages.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"portraits","required":false,"schema":{"type":"string","enum":["inline"]},"description":"inline adds `portraits`: a small data: thumbnail per signed portrait URL, for embedded views whose host blocks image origins."}]}},"/api/v1/studies/{studyId}/analytics":{"get":{"responses":{"200":{"description":"Canonical study statistics.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyAnalytics"}}}}}},"401":{"description":"Missing or invalid authentication."},"403":{"description":"The caller cannot access this study."},"404":{"description":"Study not found."}},"operationId":"getStudyAnalytics","summary":"Get canonical study analytics","description":"Compute scale, categorical, multiselect, and qualitative statistics from answered study questions.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/studies/{studyId}/ask":{"post":{"responses":{"200":{"description":"SSE stream of study generation events, or a durable queue receipt (JSON) when responseMode is queued. An explicit responseMode `stream` whose Minds are still training waits with the stream open: a `minds_preparing` event (`waitingFor`, `retraining`, `waitedMs`) per check, then the usual events; if they are not ready within 9 minutes it ends with an `error` event (409 `PANEL_MINDS_NOT_READY`, `cause: minds_training`, with the counts) and nothing is charged. Minds being retrained answer with their current version, so only brand-new Minds are waited for.","content":{"text/event-stream":{"schema":{"type":"string","description":"Server-Sent Events stream. Each `data:` payload is a JSON object matching `StudyAskSseEvent`. Lines starting with `:` are heartbeat comments sent every 15 s so long aggregation is not cut off by 100 s proxy idle timeouts; they carry no data. While attached documents are still being read the stream opens after at most 10 s of silence; an error after it opened arrives as a final `error` event with the HTTP status, message and data it would otherwise have had (for example 422 `ATTACHMENT_PROCESSING_FAILED`)."},"examples":{"result":{"summary":"Final result event","value":"data: {\"type\":\"result\",\"outputData\":{\"title\":\"Rate this 1-5\",\"type\":\"scale\",\"audiences\":[]},\"outputType\":\"bar\"}\n\n"}}},"application/json":{"schema":{"type":"object","required":["status","count","questionBlockId","clientRequestId","queuedMessage"],"properties":{"status":{"type":"string","enum":["queued","preparing"],"description":"`preparing` while the run waits for Minds that are still training; it starts on its own once they are ready."},"waitingFor":{"type":"integer","minimum":1,"description":"Minds the run waits for before it starts. Present only with `status: preparing`."},"leftOutMinds":{"type":"array","description":"Minds whose training keeps failing (they are retried automatically): the Study runs without them (at least one Mind and at least half of the Minds it asks still answer) and they are retrained automatically.","items":{"type":"object","required":["mindId","name","audienceId"],"properties":{"mindId":{"type":"string","format":"uuid"},"name":{"type":"string"},"audienceId":{"type":"string","format":"uuid"},"trainingMessage":{"type":"string"}}}},"jobId":{"type":"string"},"count":{"type":"integer","minimum":1},"questionBlockId":{"type":"string","description":"Canonical Question Block correlation ID."},"questionAudienceId":{"type":"string","deprecated":true,"description":"Legacy alias for questionBlockId."},"clientRequestId":{"type":"string","format":"uuid"},"queuedMessage":{"type":"boolean","enum":[true]}}}}},"x-event-schema":{"$ref":"#/components/schemas/StudyAskSseEvent"}},"202":{"description":"Default ask (no responseMode) while Minds of the Study are still training: the question was queued instead of streamed and runs on its own once they are ready. Same receipt as responseMode queued (`status: preparing`, `waitingFor`). Poll the Study messages for the answer.","content":{"application/json":{"schema":{"type":"object","required":["status","questionBlockId","clientRequestId","queuedMessage"],"properties":{"status":{"type":"string","enum":["queued","preparing"]},"waitingFor":{"type":"integer","minimum":1},"jobId":{"type":"string"},"questionBlockId":{"type":"string"},"clientRequestId":{"type":"string","format":"uuid"},"queuedMessage":{"type":"boolean","enum":[true]}}}}}},"400":{"description":"Missing question, invalid study ID, invalid model override, no attached audiences, or no minds in selected audiences."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the Study or an attached upload, or plan message limit reached (`code: PLAN_LIMIT`)."},"404":{"description":"Study does not exist."},"409":{"description":"No Mind of the Study can answer and none can be retrained (`data.code: PANEL_MINDS_NOT_READY`, `data.cause: no_mind_can_answer`), naming the Minds and why their training failed. Minds still training never cause a 409 status: the ask is queued (default, 202; `queued`) or waits in the stream (`stream`, which ends with a `minds_training` error event only after 9 minutes). Nothing ran and nothing was charged."},"500":{"description":"Internal server error."},"503":{"description":"The question's answer format could not be read even after a fresh reading (`code: QUESTION_READING_UNAVAILABLE`, `retryable: true`). Nothing ran and no responses were used; repeat the request. After the stream opened this arrives as the final `error` event with the same status and data."}},"operationId":"askStudy","summary":"Ask a study question","description":"Send a question to all minds in a study or a selected subset of attached audiences. Returns a Server-Sent Events stream with start, optional classification, per-mind answers, aggregation progress, final output data, and done events.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"description":"Study UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyAskRequest"},"examples":{"basic":{"summary":"Ask all audiences","value":{"question":"On a scale of 1-10, how likely are you to recommend this product?"}},"withContext":{"summary":"Ask selected audiences with context","value":{"question":"What should we improve in this onboarding flow?","audienceIds":["550e8400-e29b-41d4-a716-446655440000"],"attachments":[{"url":"https://example.com/onboarding.pdf","name":"Onboarding flow","type":"application/pdf"}],"links":[{"label":"https://competitor.example.com/onboarding","id":"competitor-onboarding"}]}}}}}}}},"/api/v1/studies/{studyId}/audiences/{audienceId}":{"delete":{"responses":{"204":{"description":"The Audience is not attached to the Study."},"400":{"description":"Invalid Study or Audience ID, or the Study is not in study mode (code FLOW_NOT_STUDY)."},"401":{"description":"Missing or invalid authentication."},"403":{"description":"The caller cannot work in this Study (code PANEL_FORBIDDEN)."},"404":{"description":"Study not found (code PANEL_NOT_FOUND)."}},"operationId":"detachStudyAudience","summary":"Remove an Audience from a Study","description":"Detaches an Audience from a Study you can work in, as the web app does. The Audience and its Minds are not deleted, and earlier answers stay in the Study. Removing an Audience that is not attached is a no-op, so a retry is safe.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"audienceId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/studies/{studyId}/audiences":{"post":{"responses":{"200":{"description":"The requested Audiences are attached.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["studyId","audienceIds","attached","alreadyAttached"],"properties":{"studyId":{"type":"string","format":"uuid"},"audienceIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Every requested Audience, de-duplicated."},"attached":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Audiences this call attached."},"alreadyAttached":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Audiences that were already attached (no-op)."}}}}}}}},"400":{"description":"Invalid Study ID or body (code VALIDATION_ERROR), or the Study is not in study mode (code FLOW_NOT_STUDY)."},"401":{"description":"Missing or invalid authentication."},"402":{"description":"A paid Marketplace Audience needs its add-on subscription (code MARKETPLACE_ADDON_REQUIRED)."},"403":{"description":"The caller cannot work in this Study (code PANEL_FORBIDDEN)."},"404":{"description":"Study not found (code PANEL_NOT_FOUND), or an Audience is not accessible (code STUDY_AUDIENCES_INACCESSIBLE, data.audienceIds)."}},"operationId":"attachStudyAudiences","summary":"Add Audiences to a Study","description":"Attaches one or more existing Audiences to a Study you can work in, as the web app does. Every Audience is checked before anything is written, so a refusal attaches none of them. Attaching an attached Audience is a no-op (reported in alreadyAttached), so a retry is safe. When the Study has link sharing enabled, newly attached Audiences and their Minds become publicly readable as well.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["audienceIds"],"properties":{"audienceIds":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"string","format":"uuid"},"description":"Audience IDs to attach. De-duplicated server-side."}}}}}}}},"/api/v1/studies/{studyId}/collaborators/{userId}":{"delete":{"responses":{"200":{"description":"Removed.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid id, or the user is the owner (`COLLABORATOR_IS_OWNER`)."},"401":{"description":"Unauthorized."},"403":{"description":"The caller can see the Study but does not manage its sharing (`COLLABORATORS_MANAGER_ONLY`)."},"404":{"description":"Study not found or not visible to the caller, or the person is not a collaborator."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"removeStudyCollaborator","summary":"Remove a collaborator from a Study","description":"Removes the person's membership and revokes their invitations for this Study in one step, so an old invitation link cannot restore access. Removing a Study collaborator also ends the read access to the Study's Audiences and Minds that being a collaborator gave them. Nobody is emailed. Only the Study owner may call it; the owner cannot be removed.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"studyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/studies/{studyId}/collaborators":{"get":{"responses":{"200":{"description":"Collaborators of the Study.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"type":"object","required":["userId","email","name","role","joinedAt"],"properties":{"userId":{"type":"string","format":"uuid","description":"Pass to DELETE …/collaborators/{userId}."},"email":{"type":["string","null"],"format":"email"},"name":{"type":["string","null"]},"role":{"type":"string","description":"Role granted by the accepted invitation."},"joinedAt":{"type":"string","format":"date-time"}}}}}}}}},"400":{"description":"Invalid id."},"401":{"description":"Unauthorized."},"403":{"description":"The caller can see the Study but does not manage its sharing (`COLLABORATORS_MANAGER_ONLY`)."},"404":{"description":"Study not found or not visible to the caller."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"listStudyCollaborators","summary":"List the people who accepted an invitation to a Study","description":"Returns every collaborator of the Study (people who accepted an email invitation), oldest first, without the owner. Pending invitations are listed by the invitations endpoints. Only the Study owner may call it; anyone else who can see the Study gets 403.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"studyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/studies/{studyId}/duplicate":{"post":{"responses":{"200":{"description":"Idempotent replay of the copy.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyCreated"}}}}}},"201":{"description":"The new copy.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyCreated"}}}}}},"400":{"description":"Invalid Study id or body."},"401":{"description":"Authentication required."},"402":{"description":"An attached marketplace Audience needs its add-on."},"403":{"description":"Plan limit reached, or an attached Audience exceeds the plan's member allowance."},"404":{"description":"Study not found, or an attached Audience is not accessible."},"409":{"description":"A run of this Study is still live. Retry when it has finished."}},"operationId":"duplicateStudy","summary":"Duplicate a Study","description":"Creates a private copy of a Study you can access, over the same Audiences and Minds, with every question, answer, chart, heatmap, summary and finished run. A schedule is copied paused. Audiences are referenced, not copied; duplicate an Audience separately to copy its Minds. Refused with 409 while a run of the Study is live. The Idempotency-Key header (or idempotencyKey) replays the same copy with status 200; a new copy returns 201.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"header","name":"Idempotency-Key","required":false,"schema":{"type":"string","maxLength":200}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Name of the copy. Defaults to \"<name> (copy)\"."},"idempotencyKey":{"type":"string","description":"Retry-safety key; the Idempotency-Key header wins."}}}}}}}},"/api/v1/studies/{studyId}/export-download":{"get":{"responses":{"302":{"description":"Redirect to a short-lived signed Storage download URL."},"400":{"description":"Job is not completed, unsupported kind/format, or the Study is not in study mode."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the Study or this export kind is disabled for their workspace."},"404":{"description":"Study, export job, or generated file does not exist."},"500":{"description":"Storage not configured, download failed, or internal server error."}},"operationId":"downloadStudyExport","summary":"Download a study export","description":"Authorize access, then redirect to a short-lived signed Storage URL for a completed export in any supported format. Pass `jobId` for one exact artifact, or `kind` and `format` for the latest completed export of that type. With no query the latest persisted full-report PDF is served. The web service never buffers the export file.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"description":"Study UUID.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"jobId","required":false,"description":"Completed export job ID. Optional when the study already has a persisted export.","schema":{"type":"string"}},{"in":"query","name":"kind","required":false,"description":"Export kind to download. Without jobId, resolves the latest completed artifact of this kind.","schema":{"type":"string","enum":["executive_brief","full_report","raw_data"]}},{"in":"query","name":"format","required":false,"description":"Export format to download. Without jobId, resolves the latest completed artifact in this format.","schema":{"type":"string","enum":["pdf","html","png","md","docx","pptx","csv","xls","sav"]}}]}},"/api/v1/studies/{studyId}/export-status":{"get":{"responses":{"200":{"description":"Export status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyExportStatusResponse"}}}},"400":{"description":"Invalid study ID or unsupported study flow."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the Study or this export kind is disabled for their workspace."},"404":{"description":"Study, export job, or completed export does not exist."},"500":{"description":"Internal server error."}},"operationId":"getStudyExportStatus","summary":"Get study export status","description":"Check the status of any queued study export. If `jobId` is omitted, the endpoint can still recover the latest legacy full-report PDF.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"description":"Study UUID.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"jobId","required":false,"description":"Specific export job ID. Omit to return the latest persisted export when available.","schema":{"type":"string"}},{"in":"query","name":"kind","required":false,"description":"Expected export kind for job-specific polling.","schema":{"type":"string","enum":["executive_brief","full_report","raw_data"]}},{"in":"query","name":"format","required":false,"description":"Expected export format for job-specific polling.","schema":{"type":"string","enum":["pdf","html","png","md","docx","pptx","csv","xls","sav"]}}]}},"/api/v1/studies/{studyId}/export":{"post":{"responses":{"200":{"description":"Export queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyExportJobResponse"}}}},"400":{"description":"Invalid study ID, unsupported study flow, or invalid export format."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the Study or this export kind is disabled for their workspace."},"404":{"description":"Study or scheduled run does not exist."},"500":{"description":"Internal server error."},"503":{"description":"Temporarily unavailable under load after automatic retries; retry the same request (code EXPORT_TEMPORARILY_UNAVAILABLE)."}},"operationId":"exportStudy","summary":"Queue a study export","description":"Queue any supported study export in the background processor. Poll `getStudyExportStatus` with the returned job ID and download the storage-backed artifact when complete.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"description":"Study UUID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyExportRequest"},"examples":{"executiveBriefPdf":{"summary":"Executive summary PDF export","value":{"kind":"executive_brief","format":"pdf"}},"fullReportDocx":{"summary":"Full report DOCX export","value":{"kind":"full_report","format":"docx"}},"rawDataCsv":{"summary":"Raw answers CSV export","value":{"kind":"raw_data","format":"csv"}},"rawDataSav":{"summary":"Raw answers SPSS export","value":{"kind":"raw_data","format":"sav"}}}}}}}},"/api/v1/studies/{studyId}/heatmaps/{messageId}/export-download":{"get":{"responses":{"200":{"description":"Website heatmap ZIP archive."}},"operationId":"downloadStudyWebsiteHeatmapExport","summary":"Download a website heatmap export","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"messageId","required":true,"schema":{"type":"string"}}]}},"/api/v1/studies/{studyId}/heatmaps/{messageId}/export-status":{"get":{"responses":{"200":{"description":"Website heatmap export status."}},"operationId":"getStudyWebsiteHeatmapExportStatus","summary":"Get website heatmap export status","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"messageId","required":true,"schema":{"type":"string"}}]}},"/api/v1/studies/{studyId}/heatmaps/{messageId}/export":{"post":{"responses":{"200":{"description":"Cached archive or queued export job."}},"operationId":"exportStudyWebsiteHeatmap","summary":"Export a website heatmap archive","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"messageId","required":true,"schema":{"type":"string"}}]}},"/api/v1/studies/{studyId}/heatmaps/{messageId}":{"get":{"responses":{"200":{"description":"Selected heatmap and queue state; GET also returns saved assetHeatmaps."}},"operationId":"getStudyHeatmap","summary":"Read saved question heatmaps; assetKey selects one video or image","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"messageId","required":true,"schema":{"type":"string"}},{"in":"query","name":"assetKey","schema":{"type":"string"}}]},"post":{"responses":{"200":{"description":"Selected heatmap and queue state; GET also returns saved assetHeatmaps."}},"operationId":"startStudyHeatmap","summary":"Analyze an assigned question asset; completed asset results are reused","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"messageId","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"assetKey":{"type":"string","description":"Stable asset key from the question attachment: upload path or normalized URL."}}}}}}}},"/api/v1/studies/{studyId}/invitations":{"post":{"responses":{"200":{"description":"Invitations created and delivery failures, if any."},"401":{"description":"Missing or invalid authentication."},"404":{"description":"Study not found or not owned by the caller."}},"operationId":"inviteStudyCollaborators","summary":"Invite study collaborators","description":"Invite people to collaborate on an existing study, matching the web app invitation flow.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["emails"],"properties":{"emails":{"type":"array","items":{"type":"string","format":"email"},"minItems":1,"maxItems":100},"role":{"type":"string","enum":["member","admin","viewer"],"default":"member"},"inviteEntireTeam":{"type":"boolean","default":false}}}}}}}},"/api/v1/studies/{studyId}/messages/{messageId}/answers":{"get":{"responses":{"200":{"description":"Sanitized question output, including per-Audience answers.","content":{"application/json":{"schema":{"type":"object","required":["messageId","outputData"],"properties":{"messageId":{"type":"string"},"outputData":{"type":"object","additionalProperties":true}}}}}},"400":{"description":"Invalid Study ID, message ID or scope."},"401":{"description":"Missing or invalid authentication."},"403":{"description":"Caller cannot access the Study."},"404":{"description":"No assistant answer with this message ID belongs to the Study."}},"operationId":"getStudyMessageAnswers","summary":"Read individual answers for one Study question","description":"Hydrates the original per-Mind responses omitted from the compact Study transcript. Requires access to the Study and an assistant message belonging to that Study. Full reads return all responses for this message; preview reads return representative responses.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"studyId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"messageId","in":"path","required":true,"schema":{"type":"string"},"description":"Assistant message CUID returned in recentResults by get_study_status."},{"name":"scope","in":"query","schema":{"type":"string","enum":["full","preview"],"default":"full"}}]}},"/api/v1/studies/{studyId}/research-plans/preview":{"post":{"responses":{"200":{"description":"Saved plan draft, per-question response contracts, and confirmation questions.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"plan":{"$ref":"#/components/schemas/ResearchStudyPlan"},"revisionCreatedAt":{"type":"string","format":"date-time","description":"When this draft revision was saved."},"attachments":{"type":"array","description":"Files the draft carries. Each file a run reads reports whether Minds can open it, before the run.","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"kind":{"type":"string","enum":["website"]},"reading":{"type":"string","enum":["read","unreadable","not_read"],"description":"unreadable: the file cannot be opened (password-protected or damaged); upload a copy without the password, or a run with it stops before any question. read: opened, nothing wrong found. not_read: not checked (format not checked, or the file could not be fetched)."}}}}}}}}}}},"400":{"description":"Invalid request."},"401":{"description":"Unauthorized."},"403":{"description":"Study access denied."},"404":{"description":"Study or draft not found."},"409":{"description":"Draft revision conflict."}},"operationId":"previewStudyResearchPlan","summary":"Preview or revise a study research plan","description":"Let the research-planning model capture intent, main source, all attached assets, questions, optional methods, semantic outputs, missing inputs, confirmation questions, and a proposed response contract for every question. Clients can deterministically edit response formats and assign durable assets to exact questions. Pass `questions` instead of `request` to transcribe a fixed instrument exactly: text, order, ids, and per-item response contracts are stored as given and no planning model runs; a revision of a fixed instrument that sends no `questions`, `request` or `refinement` (for example only `answers`) keeps its saved questions. Pass `methodId` (a Study template's `configuration.methodId`, or any method list_research_methods reports as executable) to run the first module with that registered method, as the web app does: the planner plans for it, or a fixed instrument keeps its questions as supplementary questions; methods that design their own tasks (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, TURF and others) add them at execution from the method configuration. Revisions keep the selected method unless another is named. Fetchable remote files are copied into durable Minds chat storage before the versioned draft is saved. Local file:// paths are not uploads. A draft that research-runs would refuse is never returned as confirmable: a method configuration the planner left empty is filled from the request where possible, and anything still missing (price currency, price basis, method configuration, expected respondent material) is returned as a confirmation question with `startReadiness` and `status: needs_input`; revise with `answers` keyed by question id, using the option id for a choice question. This endpoint never executes research.","tags":["Studies","Research"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"loadLatest":{"type":"boolean","description":"Read the latest owned draft without planning or saving. Requires draftPlanId; cannot be combined with edits or planner inputs."},"edits":{"type":"object","description":"Deterministic edits to a saved revision. Preserves methods and source policy; cannot be combined with planner inputs.","additionalProperties":false,"properties":{"objective":{"type":"string","maxLength":2000},"promptContent":{"type":"string","maxLength":20000},"questions":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"object","additionalProperties":false,"required":["id","moduleId","text","response"],"properties":{"id":{"type":"string"},"moduleId":{"type":"string"},"text":{"type":"string","maxLength":2000},"response":{"$ref":"#/components/schemas/ResearchQuestionResponse"},"attachmentIds":{"type":"array","items":{"type":"string"}},"askIf":{"$ref":"#/components/schemas/ResearchQuestionCondition"}}}}}},"request":{"type":"string"},"studyLocale":{"type":"string","enum":["en","es","fr","de","zh","tr","ar","ja","ko"],"description":"Language used for the plan and its eventual study output."},"sourcePolicy":{"type":"string","enum":["request_only","auto"],"default":"request_only","description":"Evidence policy stored in this exact draft revision. request_only keeps a controlled Study closed to retrieved Mind documents and live web. auto is an explicit experimental opt-in to relevant Mind-knowledge retrieval; response-mode rules still control live web search."},"videoAnalysisStyle":{"type":"string","enum":["record","analyst"],"default":"record","description":"Register of the one video summary every Mind of this run reads. record writes down the spoken script, the visible scenes and the on-screen text. analyst deliberately reproduces the pre-2026-09 prompt, which reads tone and intent and raises the study's positive rating bias; use it only to replicate an older run."},"mindSourcePolicyOverrides":{"type":"array","maxItems":2000,"description":"Experimental checksum-locked Mind assignments. Each Mind UUID may appear once. Unlisted Minds use sourcePolicy; persisted knowledge_only locks remain stricter.","items":{"type":"object","required":["mindId","sourcePolicy"],"additionalProperties":false,"properties":{"mindId":{"type":"string","format":"uuid"},"sourcePolicy":{"type":"string","enum":["request_only","auto"]}}}},"source":{"type":"object","description":"The main source. Prompt content is exact respondent-visible material and is separate from planner-only request text.","properties":{"kind":{"type":"string","enum":["prompt","website","image","video","document","questionnaire","other"]},"label":{"type":"string"},"url":{"type":"string","format":"uri"},"mimeType":{"type":"string"},"content":{"type":"string","maxLength":20000}}},"attachments":{"type":"array","maxItems":100,"description":"Files and website assets available to the confirmed run (one question block). Multi-asset blocks require complete question assignments and coverage of every asset; each question receives only its own assets. Empty lists explicitly mean no assets. Remote file URLs are durably imported; kind website remains a website.","items":{"type":"object","properties":{"kind":{"type":"string","enum":["website"]},"id":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"path":{"type":"string"},"mimeType":{"type":"string"},"type":{"type":"string"}}}},"questionAttachments":{"type":"array","description":"One-based question-to-attachment-id mapping. A question left out receives every asset. An asset placed on no question is shown with every question, including questions mapped to empty attachmentIds. Each question may appear at most once.","items":{"type":"object","required":["questionNumber","attachmentIds"],"additionalProperties":false,"properties":{"questionNumber":{"type":"integer","minimum":1},"attachmentIds":{"type":"array","minItems":0,"maxItems":20,"uniqueItems":true,"items":{"type":"string"}}}}},"suggestQuestionStimuli":{"type":"boolean","description":"Default true. Lets the planner assign each attached file or website to one or more questions; the ids appear as attachmentIds on those questions. Pass false to keep questions unassigned unless questionAttachments names them."},"draftPlanId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1},"refinement":{"type":"string"},"answers":{"type":"object","additionalProperties":{"type":"string"}},"questionResponses":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ResearchQuestionResponse"},"description":"Explicit response-format edits keyed by question ID from the current draft."},"questions":{"$ref":"#/components/schemas/FixedInstrumentQuestions"},"methodId":{"type":"string","maxLength":80,"description":"Registered research method for the first module, such as a Study template's configuration.methodId (van-westendorp, maxdiff, conjoint, nps, turf, …). Must be executable (list_research_methods); an unknown or unavailable method is a 400. Its configuration is filled from the request, questions and answers where they state it, otherwise asked as a confirmation question. Omitted on a new draft: the planner chooses, and a fixed instrument runs as Custom research (guided-research). Omitted on a revision: the method selected earlier is kept. Cannot be combined with edits or loadLatest."},"idempotencyKey":{"type":"string","maxLength":200,"description":"Retry-safety key. A repeated preview with the same key returns the draft revision the first attempt saved (`replayed: true`) instead of planning again. The `Idempotency-Key` header takes precedence."}}}}}}}},"/api/v1/studies/{studyId}/research-runs/{runId}":{"get":{"responses":{"200":{"description":"Durable study status and immutable response contracts.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"plan":{"$ref":"#/components/schemas/ResearchStudyPlan"},"executionPlan":{"$ref":"#/components/schemas/ResearchStudyPlan"},"status":{"type":"string","enum":["queued","running","completed","partial","failed","cancelled","plan_limited"],"description":"Partial means settled questions have missing respondent answers or some questions failed. It is terminal collection, not complete evidence."},"progress":{"type":"object","properties":{"total":{"type":"integer"},"settled":{"type":"integer"},"failed":{"type":"integer"},"partial":{"type":"integer","description":"Questions with recorded incomplete respondent coverage."},"skipped":{"type":"integer","description":"Questions a plan limit kept from running."},"pct":{"type":"integer","description":"Settled-question progress, not respondent coverage."}}},"planLimit":{"type":"object","additionalProperties":true,"description":"With status plan_limited: the PLAN_LIMIT envelope that stopped the run (limitType studyAnswers or responses, limit, current, resumeAvailable)."},"skippedQuestions":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"text":{"type":"string"}}},"description":"With status plan_limited: the questions not asked, by zero-based plan index. POST research-runs/{runId}/resume runs them in place once the plan allows it."},"memberKnowledge":{"type":"object","required":["consulted","sourcePolicy","description"],"description":"Whether the Minds could read their own knowledge bases on this run. A confirmed multi-question block defaults to `request_only`, so `consulted` is normally false and anything uploaded to a Mind had no effect on these answers — show `description` to the user rather than leaving that to be inferred from the answers.","properties":{"consulted":{"type":"boolean","description":"True only when at least one Mind could retrieve its own knowledge."},"sourcePolicy":{"type":"string","enum":["auto","request_only","knowledge_only"],"description":"The run default, before per-Mind overrides."},"description":{"type":"string","description":"One sentence that can be shown verbatim."},"mindOverrides":{"type":"object","description":"Present only for a preregistered per-Mind source-policy experiment; the run is then not uniform.","properties":{"count":{"type":"integer"},"consulting":{"type":"integer"}}}}},"respondentStimulusDelivery":{"type":"object","description":"Configured stimulus channel, not proof of delivery. The frozen base Mind profile excludes per-run stimulus.","properties":{"channel":{"type":"string","enum":["prompt_evidence","website_analysis","file_analysis","none"]},"mindProfileIncludesStimulus":{"type":"boolean","enum":[false]},"verification":{"type":"string","enum":["configuration_only"]},"description":{"type":"string"}}},"respondentMediaEvidence":{"type":"object","description":"Per-Mind video evidence audit. Verified means every recorded answer for every video question has matching audiovisual receipts and accepted-call SDK media prompt hashes.","properties":{"version":{"type":"string","enum":["respondent-media-evidence-v1"]},"status":{"type":"string","enum":["not_applicable","verified","incomplete"]},"videoQuestionCount":{"type":"integer"},"answerCount":{"type":"integer"},"verifiedAnswerCount":{"type":"integer"},"visualContract":{"type":"string","enum":["scene-sampled-frames"]},"speechContract":{"type":"string","enum":["full-transcript"]},"soundtrackContract":{"type":"string","enum":["bounded-analysis"]},"failures":{"type":"array","items":{"type":"object","additionalProperties":true}}}},"questionAttachments":{"type":"array","items":{"type":"object","additionalProperties":true}},"answerConsistency":{"type":"object","required":["version","status"],"description":"After a completed run, each Mind's answers are checked against each other. Counts of Minds and flags; each flagged response artifact carries answerConsistency.flags. Answers are never changed. A check that could not run at all records only version and status failed.","properties":{"version":{"type":"string","enum":["answer-consistency-v1"]},"status":{"type":"string","enum":["checked","incomplete","failed"],"description":"incomplete: the time budget or a cancellation stopped the check; unchecked Minds are counted. failed: the check could not run, or no flag could be saved."},"checkedMinds":{"type":"integer","description":"Minds whose answers were checked."},"flaggedMinds":{"type":"integer","description":"Checked Minds with at least one flag."},"flagCount":{"type":"integer","description":"Contradictions found; each pair of answers counts once."},"uncheckedMinds":{"type":"integer","description":"Minds whose check could not run; their answers are unflagged, not cleared."},"unsavedItems":{"type":"array","items":{"type":"integer"},"description":"Present only when some answer rows could not store their flags: those question indexes. The other rows keep theirs."},"usage":{"type":"object","description":"Model calls and tokens the check used.","properties":{"calls":{"type":"integer"},"inputTokens":{"type":"integer"},"outputTokens":{"type":"integer"}}}}},"artifacts":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"answerConsistency":{"type":"object","required":["version","flags"],"description":"Present on a response artifact when a Mind's answer to this question contradicts its answer to another question of the run. Flags only; the answer is unchanged.","properties":{"version":{"type":"string","enum":["answer-consistency-v1"]},"flags":{"type":"array","items":{"type":"object","required":["mindId","withItem","reason"],"properties":{"mindId":{"type":"string","description":"The Mind whose answers contradict each other."},"withItem":{"type":"integer","description":"Question index of the other answer."},"reason":{"type":"string","description":"Why the two answers contradict each other."}}}}}}}}},"calculations":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"401":{"description":"Unauthorized."},"403":{"description":"Study access denied."},"404":{"description":"Study not found."}},"operationId":"getStudyResearchStudy","summary":"Get research study status","description":"Return durable progress, the immutable confirmed plan snapshot with per-question response contracts, response artifacts, deterministic method calculations, and stage readiness for a confirmed multi-question Study run. An item with askIf carries routing on its artifact: askedCount, and the Minds not asked, which are excluded from that item's responses; an item no Mind was asked is a not_asked artifact. An item gated on an open question's category also carries gateCoding (per category, how many gate answers were coded into it, and how many into none), with none meaning a verified outside-frame reading. New verified readings include an opaque readingId referencing private source evidence; the evidence itself is not included in public results. Unavailable or unresolved gate readings fail before asking dependent respondents and use the existing retry/error lifecycle. Older artifacts may retain gateCodingUnavailable when a historical worker asked everyone after coding failed.","tags":["Studies","Research"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"runId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/studies/{studyId}/research-runs/{runId}/resume":{"post":{"responses":{"200":{"description":"The run is queued again, or was already running.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["status","studyId","runId"],"properties":{"status":{"type":"string","enum":["queued","already_running"]},"studyId":{"type":"string","format":"uuid"},"runId":{"type":"string","format":"uuid"},"jobId":{"type":"string"}}}}}}}},"400":{"description":"The Study is not a multi-question Study."},"401":{"description":"Unauthorized."},"403":{"description":"Study access denied."},"404":{"description":"Study or run not found."},"409":{"description":"The run is not waiting on a plan limit, cannot be resumed automatically (`STUDY_RESUME_UNAVAILABLE`), or the account has no paid plan yet (`ENTITLEMENT_PENDING`)."}},"operationId":"resumeStudyResearchRun","summary":"Resume a plan-limited multi-question Study run","description":"Continue a confirmed multi-question run that stopped at a plan limit (`status: plan_limited`), in place and with its original confirmed questions and answer contracts. Questions that already have answers are not asked again. Requires a paid plan; the worker re-checks every remaining allowance before each question, so a run can stop at a limit again.","tags":["Studies","Research"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"runId","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/studies/{studyId}/research-runs":{"post":{"responses":{"200":{"description":"Study queued with its immutable confirmed response contracts.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"plan":{"$ref":"#/components/schemas/ResearchStudyPlan"},"questionCount":{"type":"integer","description":"Questions accepted into this run."},"requestedQuestionCount":{"type":"integer","description":"Questions in the confirmed plan."},"skippedQuestionCount":{"type":"integer","description":"Questions left out because the Free plan Study answer allowance could not cover them. The run stops as plan_limited after the accepted questions and can be resumed once the plan allows it."},"leftOutMinds":{"type":"array","description":"Present when Minds that are still being prepared (their last training attempt failed past the automatic recovery budget) are left out of the run: at least one Mind and at least half of the Minds it asks still answer, and the left-out Minds are retrained automatically.","items":{"type":"object","properties":{"mindId":{"type":"string","format":"uuid"},"name":{"type":"string"},"audienceId":{"type":"string","format":"uuid"}}}},"skippedQuestions":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"text":{"type":"string"}}},"description":"Present when questions were skipped: their zero-based plan index and text."},"planLimit":{"type":"object","additionalProperties":true,"description":"Present when questions were skipped: the PLAN_LIMIT envelope (limitType, limit, current, remaining, periodEnd)."},"memberKnowledge":{"type":"object","required":["consulted","sourcePolicy","description"],"description":"Whether the Minds could read their own knowledge bases on this run, reported at queue time rather than after the answers arrive. A confirmed multi-question block defaults to `request_only`, so `consulted` is normally false and knowledge uploaded to these Minds has no effect on it.","properties":{"consulted":{"type":"boolean"},"sourcePolicy":{"type":"string","enum":["auto","request_only","knowledge_only"]},"description":{"type":"string","description":"One sentence that can be shown to the user verbatim."},"mindOverrides":{"type":"object","properties":{"count":{"type":"integer"},"consulting":{"type":"integer"}}}}}}}}}}}},"400":{"description":"Plan is incomplete, unconfirmed, invalid, unavailable, or not executable."},"401":{"description":"Unauthorized."},"403":{"description":"Study or draft access denied."},"404":{"description":"Study or draft not found."},"409":{"description":"Draft already confirmed for another run, or no Mind of the selected Audiences can answer and none can be retrained (legacy code `PANEL_MINDS_NOT_READY`, `data.cause: no_mind_can_answer`, with `data.notReady` naming the Minds). Minds still training never refuse a run: it is queued (`status: preparing`) and starts once they are ready. Minds still being prepared after a failed training attempt are left out when at least one Mind and at least half of the Minds it asks can answer (`leftOutMinds`), and retrained first otherwise; either way they are retrained automatically."},"422":{"description":"Required respondent-visible image, file, or URL could not be read. The Study is not queued and no quota is used."}},"operationId":"runStudyQuestions","summary":"Confirm and run a multi-question Study block","description":"Execute an exact saved research-plan revision after explicit confirmation, including every confirmed per-question response and attachment contract. The server, not the client or model, marks required capabilities reviewed and enforces advanced-method opt-in, method availability, and durable media resolution. Items are answered in order as one respondent would: every Mind answers an item in parallel and sees only its own earlier answers in this run.","tags":["Studies","Research"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["draftPlanId","revision","confirmation"],"properties":{"draftPlanId":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1},"confirmation":{"type":"object","required":["accepted"],"properties":{"accepted":{"type":"boolean","enum":[true]},"advancedMethodOptIn":{"type":"boolean"}}},"audienceIds":{"type":"array","items":{"type":"string","format":"uuid"}},"idempotencyKey":{"type":"string","format":"uuid"},"modelConnection":{"type":"object","additionalProperties":false,"required":["id","revision"],"properties":{"id":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1}},"description":"Verified caller-team connection for Mind answers and verbatim rendering. Pinned at confirmation; retries must keep the same selection. Supporting analysis retains platform models."}}}}}}}},"/api/v1/studies/{studyId}/runs":{"get":{"responses":{"200":{"description":"Durable Study runs, newest first, with pagination.hasMore and pagination.nextCursor."},"400":{"description":"Invalid query or a cursor outside this filtered Study run list."},"401":{"description":"Authentication required."},"403":{"description":"Study access denied."}},"operationId":"listStudyRuns","summary":"List durable study runs","tags":["Study Runs"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"before","required":false,"schema":{"type":"string","format":"uuid"},"description":"Continue with pagination.nextCursor from the previous page."},{"in":"query","name":"clientRequestId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Filter runs by the original question request ID."},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}]},"post":{"responses":{"200":{"description":"Research planning is required; no run was accepted."},"202":{"description":"Run accepted durably. When Minds in the attached Audiences are still training (or being retrained automatically), the run is accepted and stays `queued` until they are ready, then runs with them (`data.waitingFor` counts the Minds it waits for and `data.notReadyCount` all Minds not ready yet; `GET /runs/{runId}` shows `readinessWait` meanwhile); it waits for as long as they are being trained (there is no wait deadline), and fails with `error.code: minds_not_ready`, naming them, only when no Mind can answer and none can be retrained. `data.leftOutMinds` (mindId, name, audienceId) is present when Minds whose training keeps failing are left out so the run need not wait for them; they are retrained automatically and answer later runs once ready. No Mind stays failed: recovery retries it on a growing backoff and finishes an Audience member from its profile facts if training keeps failing."},"400":{"description":"Invalid study, question, or idempotency key."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot use the study or has reached a plan limit."},"404":{"description":"Study not found."},"409":{"description":"Idempotency key reused with different input, or no Mind of the attached Audiences can answer and none can be retrained (code `PANEL_MINDS_NOT_READY`, `data.cause: no_mind_can_answer`, with `data.notReady` naming the Minds). Minds still training never refuse a run: it is queued and waits for them. Minds still being prepared after a failed training attempt do not block a run: with at least one Mind and at least half of the Minds it asks able to answer, the run is accepted without them (`data.leftOutMinds`) and they are retrained automatically; with fewer, they are retrained first and the run waits for them."}},"operationId":"createStudyRun","summary":"Create a durable study run","description":"Atomically accepts a study question and returns a durable run that can be polled, replayed, or cancelled independently of the request connection.","tags":["Study Runs"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["question"],"properties":{"question":{"type":"string","minLength":1},"clientRequestId":{"type":"string","format":"uuid","description":"Stable idempotency key for safe retries."},"audienceIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Optional subset of attached Audiences. Defaults to all Audiences in the Study."},"attachments":{"type":"array","items":{"type":"object"}},"textAttachments":{"type":"array","description":"Pasted material the question is about (a newsletter, an email, a concept text), sent beside the question instead of inside it. Each entry is stored as a Markdown file and treated like an uploaded attachment; respondents read the documents the run reads as material to react to. Counts toward the attachment limit.","items":{"type":"object","required":["text"],"additionalProperties":false,"properties":{"name":{"type":"string","maxLength":200,"description":"File name for the stored Markdown file."},"text":{"type":"string","minLength":1}}}},"links":{"type":"array","items":{"type":"object"}},"keywords":{"type":"array","items":{"type":"object"}},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"],"default":"auto"},"modelConnection":{"type":"object","additionalProperties":false,"required":["id","revision"],"properties":{"id":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1}},"description":"Verified connection belonging to the caller team, pinned to its current revision. Mutually exclusive with model/provider. Requires the model-connections feature and team entitlement. Applies to Mind responses and verbatim rendering; supporting research analysis retains platform models."},"model":{"type":"string","description":"Optional per-request model override. Must be sent together with `provider`."},"provider":{"type":"string","enum":["openai","anthropic","google"],"description":"Provider for the model override. Must be sent together with `model`."},"historyMode":{"type":"string","enum":["last5","followup_only","none"],"default":"none","description":"How much of each Mind's own prior answers this run carries. none (default) treats every question as an independent measurement and lets the run process questions in parallel. last5 gives each Mind its own five most recent answers, which costs roughly 2.4x wall-clock and buys ~0.6pp of accuracy. followup_only carries history for conversational turns but not questionnaire items."},"responseForm":{"type":"string","enum":["concise","standard","expanded"],"description":"How long and how shaped each answer should be, for qualitative questions: `concise` one short message (5-20 words), `standard` 1-3 sentences (25-90 words), `expanded` 2-5 sentences (70-180 words). Omit to let the question decide, which is the existing behaviour. An authored form outranks the phrasing of the question, so a fixed instrument keeps its exact wording. Ignored for scale, categorical and multiselect questions."},"routeResearchBrief":{"type":"boolean","default":false,"description":"When true, a broad or generated research objective returns a reviewable planning_required response instead of being submitted verbatim to every respondent."}}}}}}}},"/api/v1/studies/{studyId}/sharing":{"put":{"responses":{"200":{"description":"Updated sharing state and public share ID."},"400":{"description":"Invalid body, or team sharing requested without a team."},"401":{"description":"Missing or invalid authentication."},"404":{"description":"Study not found or not owned by the caller."}},"operationId":"updateStudySharing","summary":"Update study link and team sharing","description":"Owner only. `isLinkSharingEnabled` enables or disables the public link; enabling it also exposes the attached Audiences and Minds, matching the web app. `isSharedWithTeam: true` lets every current and future member of the owner's team open the Study (team viewers read only); it sends no invitation or notification, and `false` removes that access at once. Sharing with the team requires the owner to be in a team (400 `TEAM_REQUIRED`). Send either field or both.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"additionalProperties":false,"properties":{"isLinkSharingEnabled":{"type":"boolean"},"isSharedWithTeam":{"type":"boolean"}}}}}}}},"/api/v1/studies/{studyId}/summary":{"get":{"responses":{"200":{"description":"Persisted semantic summary.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Study is not in study mode."},"401":{"description":"Unauthorized."},"403":{"description":"Study access denied."},"404":{"description":"Study not found."}},"operationId":"getStudySemanticSummary","summary":"Get a study semantic summary","description":"Return the persisted whole-study summary, semantic output blocks, staleness, and message coverage. Renderers are hints; consumers may introduce new UI logic without changing evidence contracts.","tags":["Studies","Research"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}]},"post":{"responses":{"200":{"description":"Generated semantic summary.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object"}}}}}},"400":{"description":"Study is not in study mode, or does not have enough content."},"401":{"description":"Unauthorized."},"403":{"description":"Study access denied."},"404":{"description":"Study not found."},"409":{"description":"A newer generation or deletion superseded this request; reload before retrying."},"413":{"description":"Summary request exceeds 4 KiB."}},"operationId":"refreshStudySemanticSummary","summary":"Generate or refresh a study semantic summary","description":"Generate and persist a whole-study summary with flexible semantic blocks. Visual-source evidence is represented as heatmaps rather than generic distribution charts.","tags":["Studies","Research"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"studyId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"force":{"type":"boolean","default":false},"length":{"type":"string","enum":["short","standard","detailed"],"default":"standard"}}}}}}}},"/api/v1/studies":{"get":{"responses":{"200":{"description":"A page of studies.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudySummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid `search`."},"401":{"description":"Missing or invalid API key."},"500":{"description":"Internal server error."}},"operationId":"listStudies","summary":"List studies","description":"List Studies owned by the authenticated user, ordered by updatedAt descending and then id descending. `search` (alias `searchQuery`) filters by name. Each Study embeds its attached Audiences and their member Minds. Offset pages may shift if Studies change between requests.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"search","required":false,"description":"Case-insensitive substring match against the Study name (trimmed, at most 200 characters). `pagination.total` counts the matches.","schema":{"type":"string","maxLength":200}},{"in":"query","name":"searchQuery","required":false,"description":"Alias of `search`, matching the `list_studies` MCP tool. Sent together with `search`, both must be equal.","schema":{"type":"string","maxLength":200}},{"in":"query","name":"limit","required":false,"description":"Max studies per page.","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"in":"query","name":"offset","required":false,"description":"Number of studies to skip.","schema":{"type":"integer","minimum":0,"default":0}}]},"post":{"responses":{"201":{"description":"Study created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyCreated"}}}}}},"400":{"description":"Missing `name`."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Plan limit reached (`code: PLAN_LIMIT`)."},"404":{"description":"One or more Audience IDs were not found or are inaccessible to the caller."},"500":{"description":"Internal server error."}},"operationId":"createStudy","summary":"Create a Study","description":"Create a Study and optionally attach existing or newly created Audiences with audienceIds and audienceConfigs.","tags":["Studies"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Study name."},"audienceIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Audience IDs to attach. De-duplicated server-side."},"audienceConfigs":{"type":"array","description":"Audiences to create atomically before attaching them to the Study.","items":{"type":"object","required":["name","mindIds"],"properties":{"name":{"type":"string"},"mindIds":{"type":"array","items":{"type":"string","format":"uuid"}}}}},"isLinkSharingEnabled":{"type":"boolean","description":"Enable public link sharing for the Study and its attached Audiences/Minds."}}}}}},"parameters":[]}},"/api/v1/study-drafts/{id}":{"delete":{"responses":{"204":{"description":"Study draft deleted."},"401":{"description":"Unauthorized."},"404":{"description":"Study draft not found."},"500":{"description":"Internal server error."}},"operationId":"deleteStudyDraft","summary":"Delete a Study draft","tags":["Study Drafts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}]},"get":{"responses":{"200":{"description":"Owned Study draft.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyDraft"}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Study draft not found."},"500":{"description":"Internal server error."}},"operationId":"getStudyDraft","summary":"Get a Study draft","tags":["Study Drafts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}]},"patch":{"responses":{"200":{"description":"Updated Study draft.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyDraft"}}}}}},"400":{"description":"Malformed JSON or invalid input."},"401":{"description":"Unauthorized."},"404":{"description":"Study draft not found."},"409":{"description":"Stale revision or consumed draft."},"413":{"description":"Request exceeds 1 MiB or payload exceeds 512 KiB."},"500":{"description":"Internal server error."}},"operationId":"updateStudyDraft","summary":"Update a Study draft","description":"Save an exact planning snapshot using optimistic revision compare-and-swap. A changed snapshot increments revision and returns the snapshot written by that update; an identical snapshot preserves revision and updatedAt. JSON requests are limited to 1 MiB and the versioned payload to 512 KiB. Responses are private and not cached.","tags":["Study Drafts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["expectedRevision"],"properties":{"expectedRevision":{"type":"integer","minimum":1},"name":{"type":"string"},"mode":{"type":"string","enum":["quick","custom"]},"currentStep":{"type":"string"},"payload":{"$ref":"#/components/schemas/StudyDraftPayload"}}}}}}}},"/api/v1/study-drafts/{id}/consume":{"post":{"responses":{"200":{"description":"Consumed Study draft."},"400":{"description":"Malformed JSON or invalid input."},"401":{"description":"Unauthorized."},"404":{"description":"Study draft not found."},"409":{"description":"Stale revision."},"413":{"description":"Request exceeds 4 KiB."},"500":{"description":"Internal server error."}},"operationId":"consumeStudyDraft","summary":"Consume a Study draft after launch","description":"Idempotently closes a draft after its Study crosses the durable execution boundary. The consumed tombstone prevents delayed clients from recreating the draft. Requires JSON up to 4 KiB. Responses are private and not cached.","tags":["Study Drafts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["expectedRevision"],"properties":{"expectedRevision":{"type":"integer","minimum":1},"studyId":{"type":["string","null"],"format":"uuid"}}}}}}}},"/api/v1/study-drafts/{id}/read-source":{"post":{"responses":{"200":{"description":"Fresh reading with preserved edits; unresolved settings require confirmation."},"401":{"description":"Unauthorized."},"404":{"description":"Study draft not found."},"409":{"description":"Draft changed or cannot be edited."},"422":{"description":"Source cannot be verified; the saved review is unchanged."},"429":{"description":"Rate limited."},"500":{"description":"Reading failed; retry without losing saved edits."}},"operationId":"rereadStudyDraftSource","summary":"Reread the saved source of an owned Study draft","tags":["Study Drafts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["expectedRevision"],"properties":{"expectedRevision":{"type":"integer","minimum":1}}}}}}}},"/api/v1/study-drafts":{"get":{"responses":{"200":{"description":"Active Study drafts.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudyDraft"}},"pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Active drafts matching the search."},"limit":{"type":["integer","null"],"description":"Page size requested; null when every match is returned."},"offset":{"type":"integer","description":"Number of matching drafts skipped."}}}}}}}},"400":{"description":"Invalid search, limit or offset."},"401":{"description":"Unauthorized."},"500":{"description":"Internal server error."}},"operationId":"listStudyDrafts","summary":"List active Study drafts","description":"List only draft and starting Study drafts owned by the authenticated user, newest first. search filters by name; limit and offset page the result (omit limit to list every active draft).","tags":["Study Drafts"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"search","required":false,"description":"Case-insensitive substring of the draft name (at most 200 characters).","schema":{"type":"string","maxLength":200}},{"in":"query","name":"limit","required":false,"description":"Drafts per page. Omit to list every active draft.","schema":{"type":"integer","minimum":1,"maximum":100}},{"in":"query","name":"offset","required":false,"description":"Number of matching drafts to skip.","schema":{"type":"integer","minimum":0,"default":0}}]},"post":{"responses":{"201":{"description":"Study draft created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyDraft"}}}}}},"400":{"description":"Malformed JSON or invalid draft input."},"401":{"description":"Unauthorized."},"409":{"description":"The supplied draft ID already exists."},"413":{"description":"Request exceeds 1 MiB or the versioned payload exceeds 512 KiB."},"500":{"description":"Internal server error."}},"operationId":"createStudyDraft","summary":"Create a durable Study draft","description":"Create a resumable Quick or Custom Study planning snapshot. This does not start research. Accepts optional JSON up to 1 MiB; the versioned payload is limited to 512 KiB. Responses are private and not cached.","tags":["Study Drafts"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyDraftCreateInput"}}}},"parameters":[]}},"/api/v1/study-templates/{id}":{"delete":{"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}}}}}}},"400":{"description":"Invalid template configuration or request."},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"409":{"description":"Revision changed or a saved Audience/file is unavailable."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"deleteStudyTemplate","summary":"Delete a personal Study template","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"get":{"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyTemplate"}}}}}},"400":{"description":"Invalid template configuration or request."},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"409":{"description":"Revision changed or a saved Audience/file is unavailable."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"getStudyTemplate","summary":"Get a personal Study template","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"patch":{"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyTemplate"}}}}}},"400":{"description":"Malformed JSON or invalid template configuration or request."},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"409":{"description":"Revision changed or a saved Audience/file is unavailable."},"413":{"description":"Request exceeds 1 MiB."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"updateStudyTemplate","summary":"Rename or replace a Study template","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyTemplateUpdateInput"}}}}}},"/api/v1/study-templates/{id}/invitations/{invitationId}":{"delete":{"responses":{"200":{"description":"Cancelled; the invitation link no longer works. Revoking a cancelled invitation succeeds again.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Template or invitation not found, or the template is not owned by the caller."},"409":{"description":"The invitation is no longer pending."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"revokeStudyTemplateInvitation","summary":"Revoke a pending Study template invitation (owner only)","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"invitationId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/study-templates/{id}/invitations":{"get":{"responses":{"200":{"description":"Accepted members (`kind: member`, `id` is their user id, removable with DELETE …/members/{userId}) and pending, unexpired invitations (`kind: invitation`, revocable with DELETE …/invitations/{invitationId}). Team access is the template's `isSharedWithTeam`.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudyTemplateAccessEntry"}}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"listStudyTemplateAccess","summary":"List who has email access to a Study template (owner only)","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]},"post":{"responses":{"200":{"description":"Invitations created. Each address gets an invitation email valid for seven days; re-inviting refreshes the link. An accepted invitee can read and use the template but not change, delete or share it. Addresses in `emailFailures` were invited but their email was not delivered.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyTemplateInvitationResult"}}}}}},"400":{"description":"Malformed JSON, invalid email or only your own address."},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"413":{"description":"Request exceeds 16 KiB."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"inviteToStudyTemplate","summary":"Share a Study template by email (owner only)","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyTemplateInviteInput"}}}}}},"/api/v1/study-templates/{id}/members/{userId}":{"delete":{"responses":{"200":{"description":"Removed. The person can no longer list, read or use the template, and the invitations they accepted are revoked; drafts they already created stay theirs. File links already handed out (template attachments) follow the same signed-URL rules as Study files and are not revoked.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}}}}}}},"401":{"description":"Unauthorized."},"404":{"description":"Template or member not found, or the template is not owned by the caller."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"removeStudyTemplateMember","summary":"Remove a person's email access to a Study template (owner only)","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}]}},"/api/v1/study-templates/{id}/use":{"post":{"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyDraft"}}}}}},"400":{"description":"Malformed JSON or invalid template configuration or request."},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"409":{"description":"Revision changed or a saved Audience/file is unavailable."},"413":{"description":"Request exceeds 4 KiB."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"instantiateStudyTemplate","summary":"Create an independent draft from a Study template","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyTemplateUseInput"}}}}}},"/api/v1/study-templates":{"get":{"responses":{"200":{"description":"Success.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/StudyTemplate"}},"pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Templates matching the search."},"limit":{"type":["integer","null"],"description":"Page size requested; null when every match is returned."},"offset":{"type":"integer","description":"Number of matching templates skipped."}}}}}}}},"400":{"description":"Invalid template configuration or request."},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"409":{"description":"Revision changed or a saved Audience/file is unavailable."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"listStudyTemplates","summary":"List your personal Study templates","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"search","required":false,"description":"Case-insensitive substring of the template name (at most 200 characters).","schema":{"type":"string","maxLength":200}},{"in":"query","name":"limit","required":false,"description":"Templates per page. Omit to list every visible template.","schema":{"type":"integer","minimum":1,"maximum":100}},{"in":"query","name":"offset","required":false,"description":"Number of matching templates to skip.","schema":{"type":"integer","minimum":0,"default":0}}]},"post":{"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/StudyTemplate"}}}}}},"400":{"description":"Malformed JSON or invalid template configuration or request."},"401":{"description":"Unauthorized."},"404":{"description":"Template not found or not owned by the caller."},"409":{"description":"Revision changed or a saved file is unavailable."},"413":{"description":"Request exceeds 1 MiB."},"500":{"description":"Internal server error. Responses are private and non-cacheable."}},"operationId":"saveStudyTemplate","summary":"Save a personal Custom Study template","description":"Templates are private by default. Owners may share one with their current team, or by email with specific people; current teammates and accepted invitees can read and use it. Only owners may update, delete, change sharing or manage who has access. The questionnaire is copied into an independent draft on use; using a template never starts research. Predefined templates are adapted in the app to the Study's goal, context and selected Audiences: contextual questions name the product, task, price or compared options the context states, in the language of the brief; standardized instrument items (SUS, SEQ) keep their wording, in a published validated translation where one exists and otherwise in their original language; and when adaptation fails or would change the template structure, the saved questions are used as written. Custom templates retain their saved wording unless adaptation is requested. Uploaded assets are copied on save and use. A template also carries the research method it was built with: a calculator-backed method that designs its own tasks at execution (Van Westendorp, Gabor-Granger, MaxDiff, conjoint, Kano, NPS, top-box, key drivers, TURF) writes those questions when the Study runs, and the saved questions are asked alongside them.","tags":["Study Templates"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StudyTemplateCreateInput"}}}},"parameters":[]}},"/api/v1/support/audiences":{"get":{"responses":{"200":{"description":"data.grants includes audienceName, audienceId, grant id, reason and expiry; data.nextCursor."},"403":{"description":"Verified staff access required."}},"operationId":"listStaffAudienceSupport","summary":"List Audiences authorized for staff support","description":"Confirmed, active getminds.ai staff only. Lists only customer-granted, unexpired and unrevoked access whose original owner still owns the Audience. Up to 50 grants; pass nextCursor as cursor.","tags":["Support"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"name":"cursor","in":"query","schema":{"type":"string","format":"uuid"}}]}},"/api/v1/uploads/import":{"post":{"responses":{"200":{"description":"Every file imported.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["files"],"properties":{"files":{"type":"array","items":{"type":"object","required":["name","path","url","mimeType"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"mimeType":{"type":"string"},"path":{"type":"string","description":"Storage path, chat/{userId}/..."},"url":{"type":"string","description":"Durable /api/uploads/chat/... URL."}}}}}}}}}}},"400":{"description":"Invalid request, or a file could not be downloaded, returned a non-200 status, or is empty."},"401":{"description":"Authentication required."},"403":{"description":"A referenced Minds upload does not belong to the caller."},"413":{"description":"A file exceeds the 100 MB limit."}},"operationId":"importUploads","summary":"Import files by URL into durable account storage","description":"Copies up to 20 files from public HTTP(S) URLs (for example the short-lived download link of a chat host) into the upload storage of the caller and returns durable Minds upload URLs to pass wherever a file URL is accepted (Audience briefs, Study drafts, validations, Mind knowledge, source imports). Downloads are SSRF-protected and limited to 100 MB per file; private-network URLs are refused. A file already in that storage is confirmed rather than copied. Imports are content-addressed, so retrying the same file returns the same path. All files are imported or none is reported: the first failing file is named by its one-based position (\"Study asset N ...\").","tags":["Uploads"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["files"],"additionalProperties":false,"properties":{"files":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":"string","description":"Public HTTP(S) URL, or a Minds upload URL/path the caller owns."},"name":{"type":"string","description":"File name to store; derived from the URL when omitted."},"type":{"type":"string","description":"MIME type when known; otherwise taken from the download."},"id":{"type":"string","description":"Caller identifier echoed back on the imported file."}}}}}}}}},"parameters":[]}},"/api/v1/user/shareable-sparks":{"get":{"responses":{"200":{"description":"Owned Minds in data, plus pagination."},"400":{"description":"Invalid pagination or filter."},"401":{"description":"Unauthorized."}},"operationId":"listShareableMinds","summary":"List owned Minds available for embedding","tags":["Minds"],"security":[{"ApiKeyAuth":[]}],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"default":0}},{"in":"query","name":"includePrivate","schema":{"type":"string","enum":["true","false","1","0"]}}]}}},"components":{"schemas":{"ApiKeySummary":{"type":"object","required":["id","name","createdAt","lastUsedAt"],"properties":{"id":{"type":"string","description":"API key ID (cuid: `c` followed by 24 lowercase alphanumerics). Use it with `DELETE /v1/api-keys/{keyId}`."},"name":{"type":["string","null"],"description":"Human-readable label, or null for an unnamed key."},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time","description":"Last time the key authenticated a request; null if never used."}}},"ApiKeyCreated":{"type":"object","required":["id","name","createdAt","key"],"properties":{"id":{"type":"string","description":"API key ID (cuid). Use it with `DELETE /v1/api-keys/{keyId}`."},"name":{"type":["string","null"],"description":"Label as stored (trimmed), or null."},"createdAt":{"type":"string","format":"date-time"},"key":{"type":"string","pattern":"^minds_[0-9a-f]{48}$","description":"Raw secret, `minds_` followed by 48 hex characters. Send it as `Authorization: Bearer <key>`. Shown only once."}}},"AudienceDetail":{"type":"object","required":["id","name","mindCount","minds","createdAt","updatedAt","isPublic","currentMemberRole","sources","calibration"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"marketplaceSubtitle":{"type":["string","null"],"description":"Short subtitle shown in the public marketplace listing."},"marketplaceDescription":{"type":["string","null"],"description":"Longer description shown in the public marketplace listing."},"mindCount":{"type":"integer","minimum":0},"membersLoaded":{"type":"boolean","description":"Present in preview mode. False means the member array is incomplete; mindCount remains authoritative."},"minds":{"type":"array","description":"Member Minds ordered by name.","items":{"$ref":"#/components/schemas/AudienceDetailMember"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isPublic":{"type":"boolean","description":"Anyone signed in can open the Audience and its Minds (marketplace listing)."},"currentMemberRole":{"type":"string","enum":["owner","admin","member","team_member","public_viewer"],"description":"The caller's relationship to this Audience. `public_viewer` also covers read-only access inherited from a containing Study."},"isSharedWithTeam":{"type":"boolean","description":"Collaborators only. Every member of the owner's team can open the Audience and read and chat with every Mind in it; no edit rights on the Minds."},"isLinkSharingEnabled":{"type":"boolean","description":"Collaborators only. Anyone with the public link can open the Audience."},"publicShareId":{"type":["string","null"],"description":"Collaborators only. Token of the public share link, when link sharing has been enabled."},"grounding":{"allOf":[{"$ref":"#/components/schemas/AudienceDetailGrounding"}],"description":"Stored research grounding. Absent when the Audience was never grounded."},"sources":{"type":"array","description":"The Audience's source bundle in creation order: the original brief, later recalibration adjustments, keywords, links and uploaded files. Uploaded-file URLs are signed and are redacted for public and Study-cascade viewers.","items":{"$ref":"#/components/schemas/AudienceSourceRecord"}},"derivedDistributions":{"type":"array","description":"Baseline demographics derived from what the members actually are, for dimensions the research did not cover. Present only when the member count is within the derivation cap and at least one dimension could be derived. A `grounding` chart that holds one value every member shares (an age range, \"Region: United States and Europe\", \"1-20 staff\") is a membership constraint, marked `kind: 'eligibility'` and shown as \"All members: …\", never as a 100% chart; where the Minds carry finer values for that dimension and no quota chart already shows them, an entry here gives the members' own breakdown (ages in standard bands), with the constraint in its `interpretation`. Not research evidence and never used for cohort allocation.","items":{"$ref":"#/components/schemas/GroundingDistribution"}},"calibration":{"$ref":"#/components/schemas/AudienceCalibrationState"},"research":{"type":"object","description":"Where the Audience's research stands (same shape as `research` on `GET /audiences/{audienceId}/progress`). `researching`: the Audience is usable and its background web research is running; `researched`: done; `usable`: it failed and the Audience stays on what was already known.","properties":{"phase":{"type":"string","enum":["usable","researching","researched"]},"status":{"type":["string","null"],"enum":["queued","running","completed","failed",null]},"stage":{"type":["string","null"],"enum":["researching","waiting_for_runs","recalibrating","done",null]},"progress":{"type":"integer","minimum":0,"maximum":100},"startedAt":{"type":["string","null"],"format":"date-time"},"operation":{"type":["object","null"],"description":"Owner-only latest durable recalibration: receipt, status, result.grounding and member counts, or safe terminal error."},"completedAt":{"type":["string","null"],"format":"date-time"},"outcome":{"type":["object","null"],"additionalProperties":true}}}}},"AudienceDetailMember":{"type":"object","required":["id","name","discipline","profileImageUrl","createdAt","cohortProfile"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"discipline":{"type":["string","null"]},"profileImageUrl":{"type":["string","null"],"format":"uri","description":"Absolute avatar URL, or null while the portrait is still being generated."},"createdAt":{"type":"string","format":"date-time"},"readyToChat":{"type":"boolean","description":"The member can answer, as `GET /minds/{mindId}/training` reports it. A Study waits for members still training; members that failed training for good are left out when at least one Mind and at least half of the members can answer, and retrained automatically where possible."},"cohortProfile":{"oneOf":[{"$ref":"#/components/schemas/CohortMemberProfile"},{"type":"null"}],"description":"The segment of every grounded distribution this member represents. Null for Minds that were never allocated."}}},"CohortMemberProfile":{"type":"object","required":["memberIndex","assignments"],"properties":{"memberIndex":{"type":"integer","minimum":0},"assignments":{"type":"array","items":{"type":"object","required":["distribution","segment","sourceIdx"],"properties":{"distribution":{"type":"string","description":"Name of the grounded distribution."},"segment":{"type":"string","description":"Label of the assigned segment."},"sourceIdx":{"type":"integer","description":"Index into the grounding sources; -1 for assumed or derived segments."},"dimension":{"type":"string","enum":["age","gender","income","life_stage","representation","education","employment_status","marital_status","household_size","household_income","geography","occupation","industry","gender_identity","source_sex","nationality","visual_presentation","duration_years","none"],"description":"Shared attribute dimension (GROUNDING_DIMENSIONS). gender_identity and source_sex are one gender attribute; gender is appearance."},"canonical":{"type":"string","description":"Language-independent segment concept, e.g. `feminine` or an age band such as `65+`."}}}}}},"AudienceDetailGrounding":{"type":"object","required":["snapshotId","distributions","reviewDistributions","sources","summary","confidence","appliedToPersonas","createdAt"],"properties":{"snapshotId":{"type":["string","null"],"description":"Identifier of the grounding snapshot currently applied."},"distributions":{"type":"array","description":"Active distributions that drive cohort allocation, bounded to the Audience definition.","items":{"$ref":"#/components/schemas/GroundingDistribution"}},"reviewDistributions":{"type":"array","description":"Complete source-identified distribution universe, including options that are not allocated.","items":{"$ref":"#/components/schemas/GroundingDistribution"}},"studyUse":{"type":"object","description":"Collaborators only. Disclosed new-research or reconstruction mode, matching the reviewed preview."},"sourceFindings":{"type":"array","items":{"type":"object"},"description":"Collaborators only. Original observed and historical findings retained separately from the active composition."},"researchStudyAnalysis":{"type":["object","null"],"description":"Classification of uploaded research files and their audience, quota, routing and evidence contracts."},"screeningAdvisories":{"type":"array","items":{"type":"object"},"description":"Collaborators only. Screening rules that read answers the Study collects: advisory, not applied to the members, kept with the Audience for the Study (same entries as the from-brief grounding)."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/GroundingSource"}},"summary":{"type":["string","null"]},"confidence":{"type":"number","minimum":0,"maximum":1},"appliedToPersonas":{"type":"boolean","description":"True when deterministic cohort allocation assigned the members to the distributions."},"allocationConfig":{"type":["object","null"],"description":"Deterministic cohort allocation controls used for the current member profiles."},"hardConstraints":{"oneOf":[{"$ref":"#/components/schemas/GroundingHardConstraints"},{"type":"null"}]},"allocationAudit":{"type":["object","null"],"description":"Per-distribution audit of target versus achieved segment counts."},"coverage":{"type":["object","null"],"description":"How each relevant standard dimension is covered: `sourced` (evidence for these people), `proxy` (a wider or related population), `assumed` (the model's stated assumption, replaced when research finds evidence) or `missing`.","properties":{"dimensions":{"type":"array","items":{"type":"object","properties":{"dimension":{"type":"string"},"status":{"type":"string","enum":["sourced","proxy","assumed","missing"]},"distribution":{"type":"string"}}}},"counts":{"type":"object","properties":{"sourced":{"type":"integer"},"proxy":{"type":"integer"},"assumed":{"type":"integer"},"missing":{"type":"integer"}}}}},"createdAt":{"type":"string","format":"date-time"}}},"GroundingHardConstraints":{"type":"object","description":"Inclusion rules resolved from the Audience specification. Values outside these bounds are excluded from allocation.","required":["gender","age","country","categoricalMemberships"],"properties":{"gender":{"type":["string","null"],"enum":["feminine","masculine","androgynous",null]},"age":{"oneOf":[{"type":"object","required":["min","max"],"properties":{"min":{"type":"integer"},"max":{"type":"integer"}}},{"type":"null"}]},"country":{"type":["string","null"]},"categoricalMemberships":{"type":"array","items":{"type":"object","required":["axisTerms","allowedValueTerms"],"properties":{"axisTerms":{"type":"array","items":{"type":"string"}},"allowedValueTerms":{"type":"array","items":{"type":"string"}}}}}}},"AudienceSourceRecord":{"type":"object","required":["id","kind","text","url","filename","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["brief","adjustment","keyword","link","file"]},"text":{"type":["string","null"],"description":"Brief, adjustment or keyword text. Null for link and file rows."},"url":{"type":["string","null"],"description":"Link URL or uploaded-file URL. Null for text rows; redacted for viewers without collaborator access."},"filename":{"type":["string","null"],"description":"Original file name for file rows."},"createdAt":{"type":"string","format":"date-time"}}},"AudienceCalibrationState":{"type":"object","required":["active","startedAt"],"properties":{"active":{"type":"boolean","description":"True while a recalibration run is in flight for this Audience."},"startedAt":{"type":["string","null"],"format":"date-time"},"operation":{"type":["object","null"],"description":"Owner-only latest durable recalibration: receipt, status, result.grounding and member counts, or safe terminal error."}}},"Formation":{"type":"object","description":"A persisted segmentation of one Audience into subgroups.","required":["id","name","status","source","visibility","canMutate","createdAt","updatedAt","createdByUserId","subgroups","hypothesis","progress"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["building","ready","failed"]},"source":{"type":"string","enum":["auto","manual"]},"visibility":{"type":"string","enum":["shared","viewer_private"]},"canMutate":{"type":"boolean","description":"Whether the caller may recompute or delete this Formation."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdByUserId":{"type":"string","format":"uuid"},"subgroups":{"type":"array","description":"Materialised subgroups in display order. A first build may have none; recompute retains the previous completed buckets until replacement succeeds.","items":{"$ref":"#/components/schemas/FormationSubgroup"}},"hypothesis":{"oneOf":[{"$ref":"#/components/schemas/StoredFormationHypothesis"},{"type":"object","maxProperties":0}],"description":"Only proposal fields are returned; legacy empty or invalid proposals become an empty object."},"progress":{"oneOf":[{"$ref":"#/components/schemas/FormationBuildProgress"},{"type":"null"}],"description":"Live build progress while `building`, the failure reason when `failed`, null once `ready`."}}},"FormationSubgroup":{"type":"object","required":["id","label","definition","isAuxiliary","position","memberships"],"properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"definition":{"type":["string","null"],"description":"Natural-language membership rule."},"isAuxiliary":{"type":"boolean","description":"True for the catch-all bucket (e.g. Other or Unanswered)."},"position":{"type":"integer","minimum":0},"memberships":{"type":"array","description":"Minds assigned to this subgroup. A Mind may appear in several subgroups when overlap is allowed.","items":{"type":"object","required":["mindId","confidence"],"properties":{"mindId":{"type":"string","format":"uuid"},"confidence":{"type":["number","null"],"minimum":0,"maximum":1}}}}}},"StoredFormationHypothesis":{"type":"object","required":["intent","subgroups"],"properties":{"intent":{"type":"string","minLength":1},"subgroups":{"type":"array","minItems":1,"maxItems":15,"items":{"type":"object","required":["id","label","definition"],"properties":{"id":{"type":"string","minLength":1},"label":{"type":"string","minLength":1},"definition":{"type":"string","minLength":1}}}}}},"FormationBuildProgress":{"type":"object","required":["phase","done","total"],"properties":{"phase":{"type":"string","enum":["classify","reconcile","ask"]},"done":{"type":"integer","minimum":0},"total":{"type":"integer","minimum":0},"failureReason":{"type":"string","description":"Safe public explanation when failed; raw diagnostics are never returned."}}},"FormationSummary":{"type":"object","required":["id","name","status","source","dimensionKey","visibility","createdAt","updatedAt","createdByUserId","subgroups","canMutate"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"status":{"type":"string","enum":["building","ready","failed"],"description":"Build state. Subgroup memberships are only populated once `ready`."},"source":{"type":"string","enum":["auto","manual"]},"dimensionKey":{"type":["string","null"],"description":"Set on auto-seeded Formations (e.g. `age`, `gender`, or `grounding:<axis>` for grounding-derived splits); null for user-created ones."},"visibility":{"type":"string","enum":["shared","viewer_private"],"description":"`shared` Formations are visible to every Audience viewer; `viewer_private` ones only to their creator."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdByUserId":{"type":"string","format":"uuid"},"canMutate":{"type":"boolean","description":"Whether the caller may recompute or delete this Formation."},"subgroups":{"type":"array","items":{"type":"object","required":["id","label","isAuxiliary","position","_count"],"properties":{"id":{"type":"string","format":"uuid"},"label":{"type":"string"},"isAuxiliary":{"type":"boolean","description":"True for the catch-all bucket (e.g. Other or Unanswered)."},"position":{"type":"integer","minimum":0},"_count":{"type":"object","required":["memberships"],"properties":{"memberships":{"type":"integer","minimum":0,"description":"Number of Minds in this subgroup."}}}}}}}},"FormationHypothesis":{"type":"object","description":"A proposed split of the Audience into 2 to 15 subgroups.","required":["intent","subgroups"],"properties":{"intent":{"type":"string","minLength":1,"description":"One line restating the split, e.g. \"Audience by gender\"."},"subgroups":{"type":"array","minItems":2,"maxItems":15,"items":{"type":"object","required":["id","label","definition"],"properties":{"id":{"type":"string","minLength":1,"description":"Stable lowercase slug, e.g. `woman` or `25-34`."},"label":{"type":"string","minLength":1,"description":"Short human-facing name."},"definition":{"type":"string","minLength":1,"description":"One-sentence decision rule for membership in this subgroup."}}}}}},"PlanLimitError":{"type":"object","description":"Error body of a plan-limit refusal (HTTP 403).","properties":{"statusCode":{"type":"integer","enum":[403]},"statusMessage":{"type":"string","description":"Human-readable message naming the plan and the limit."},"data":{"$ref":"#/components/schemas/PlanLimitEnvelope"}}},"PlanLimitEnvelope":{"type":"object","required":["code","limitType","currentPlan","limit"],"properties":{"code":{"type":"string","enum":["PLAN_LIMIT"]},"limitType":{"type":"string","description":"Which cap was hit, e.g. `audienceMembers` or `minds` (legacy responses may say `audienceMembers`)."},"currentPlan":{"type":"string"},"limit":{"type":"integer"},"current":{"type":"integer","description":"Consumption against the cap."},"requested":{"type":"integer","description":"How many units this request asked for."},"itemsToCreate":{"type":"integer","description":"Bulk-create size that pushed the request over the cap."},"periodEnd":{"type":"string","format":"date-time","description":"End of the metering window when the cap is periodic."},"context":{"type":"string"},"reason":{"type":"string"},"audienceId":{"type":"string","format":"uuid"},"isTrialing":{"type":"boolean"}}},"AudienceFromBriefResult":{"type":"object","required":["id","name","mindCount","minds","createdAt","updatedAt","isPublic","isSharedWithTeam","isLinkSharingEnabled","currentMemberRole","grounding","audienceCreationMode"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"mindCount":{"type":"integer"},"minds":{"type":"array","items":{"$ref":"#/components/schemas/AudienceMindSummary"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isPublic":{"type":"boolean"},"isSharedWithTeam":{"type":"boolean"},"isLinkSharingEnabled":{"type":"boolean"},"publicShareId":{"type":["string","null"]},"currentMemberRole":{"type":"string","enum":["owner"]},"research":{"type":"object","description":"Where the Audience's research stands. `researching`: it is usable now and its web research continues in the background (follow `research` on `GET /audiences/{audienceId}/progress`); `researched`: research finished with the creation.","properties":{"phase":{"type":"string","enum":["usable","researching","researched"]},"status":{"type":["string","null"],"enum":["queued","running","completed","failed",null]},"stage":{"type":["string","null"],"enum":["researching","waiting_for_runs","recalibrating","done",null]},"progress":{"type":"integer","minimum":0,"maximum":100}}},"grounding":{"oneOf":[{"$ref":"#/components/schemas/AudienceGrounding"},{"type":"null"}]},"audienceCreationMode":{"type":"string","enum":["balanced","segment_coverage","benchmark_depth"],"description":"The EFFECTIVE creation mode applied by the server (after the plan gate — may differ from the requested mode on plans below Pro)."},"replayed":{"type":"boolean","description":"Present and true only on an idempotent replay (200): the audience was created by an earlier request with the same idempotency key."},"datasetSegmentation":{"oneOf":[{"type":"object","properties":{"selectedVariableCount":{"type":"integer"},"observedProfileCount":{"type":"integer"},"recommendedMindCount":{"type":"integer"},"createdMindCount":{"type":"integer"}}},{"type":"null"}]},"withheldFromMemberKnowledge":{"type":["array","null"],"description":"Supplied sources that shaped grounding and study design but were deliberately kept out of the member Minds' knowledge, so they cannot leak the study's own outcomes or raw respondent rows into the predictions. Empty when everything supplied reached member knowledge; null on an idempotent replay, which means unknown rather than nothing. A non-empty list with `includeWebSearch: true` is normal; with `includeWebSearch: false` and nothing else surviving, the Audience is still created from the brief and its charts, its summary says the members carry no readable evidence, and each Mind's knowledge state says so.","items":{"type":"object","required":["title","reason"],"properties":{"title":{"type":"string","description":"File name, link title or keyword as supplied."},"reason":{"type":"string","enum":["respondent_dataset","study_report","questionnaire","screener","distribution_source","tabular","unclassified"],"description":"`unclassified` means the research-study analysis never classified it as supporting material; a file reaches member knowledge only on a positive classification, never by default."}}}},"memberTraining":{"oneOf":[{"type":"object","required":["enqueued","queuedMemberCount","pollUrlTemplate"],"description":"Per-Mind background training enqueued for this creation. Every creation path trains every member: training is committed with the Audience and resumes on its own if the build is interrupted, so `queuedMemberCount` equals `mindCount`. Null on idempotent replays (training bookkeeping is not persisted).","properties":{"enqueued":{"type":"boolean"},"queuedMemberCount":{"type":"integer"},"pollUrlTemplate":{"type":["string","null"],"description":"Substitute each member id to poll its training progress, e.g. /api/v1/minds/{mindId}/training."}}},{"type":"null"}]},"cohortAllocation":{"oneOf":[{"type":"object","required":["config","audit"],"properties":{"config":{"type":"object"},"audit":{"type":"object"},"profiles":{"type":"array","items":{"type":"object"}}}},{"type":"null"}]},"cohortAllocationCoverage":{"type":"object","description":"Which members the deterministic cohort allocation actually covered. Members flagged as real people are excluded individually (they cannot be given an invented demographic profile); `skipReason` explains a null `cohortAllocation`.","required":["memberCount","allocatedMemberCount","excludedRealPersonCount","skipReason"],"properties":{"memberCount":{"type":"integer"},"allocatedMemberCount":{"type":"integer"},"excludedRealPersonCount":{"type":"integer"},"excludedRealPersonNames":{"type":"array","items":{"type":"string"}},"skipReason":{"type":["string","null"],"enum":["no_grounded_distributions","all_members_flagged_real_person",null]}}}}},"AudienceMindSummary":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"discipline":{"type":["string","null"]},"profileImageUrl":{"type":["string","null"]}}},"AudienceGrounding":{"type":"object","required":["distributions","sources","summary","confidence"],"properties":{"distributions":{"type":"array","items":{"$ref":"#/components/schemas/GroundingDistribution"}},"reviewDistributions":{"type":"array","description":"Complete source-identified distribution universe, including screener-excluded, conditional, and unweighted options that were not allocated.","items":{"$ref":"#/components/schemas/GroundingDistribution"}},"researchStudyAnalysis":{"type":["object","null"],"description":"Canonical content-based classification of uploaded research files and their audience, quota, routing, and evidence contracts."},"research":{"type":["object","null"],"description":"Research coverage and axisReconciliation audit. An unavailable or budget_exceeded axis review is not a successful semantic validation; failureReason explains unusable model output or infrastructure failure. `dimensionCoverage.dimensions` lists the standard dimensions covered for this population — the fixed core pool every audience of people carries (age, gender identity, representation, geography, education, employment status, income, household size) plus any the planner judged relevant — each with a reason and a status: `sourced`, `proxy` (wider area or population), `assumed` (model-proposed shares, never used for sizing) or `missing`."},"sources":{"type":"array","items":{"$ref":"#/components/schemas/GroundingSource"}},"summary":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"suggestedMinAudienceSize":{"type":"integer","minimum":3,"maximum":50},"screeningAdvisories":{"type":"array","description":"Screening rules that read answers the Study collects (for example a screen-out on willingness to pay combined with income). Minds do not carry Study answers as profile attributes, so these rules are advisory: the Audience is created, the rule is not applied to its members, and it stays in `researchStudyAnalysis.allocationRules` (disposition `advisory`, `studyAnswers`) for the Study. Rules on profile attributes are enforced and never listed here.","items":{"type":"object","required":["ruleId","disposition","appliesTo","studyQuestions","reason","notice"],"properties":{"ruleId":{"type":"string"},"disposition":{"type":"string","enum":["advisory"]},"appliesTo":{"type":"string","enum":["study_answers"]},"studyQuestions":{"type":"array","items":{"type":"string"}},"reason":{"type":"string"},"notice":{"type":"string"}}}},"flaggedDistributions":{"type":"array","description":"Axes demoted to supplementary context because they measure the Study outcome itself (`audienceContext.reason = study_outcome`). Never used for cohort allocation.","items":{"type":"object","required":["name","reason"],"properties":{"name":{"type":"string"},"reason":{"type":"string","enum":["study_outcome"]},"category":{"type":"string","enum":["demographic","geographic","psychographic","behavioral","firmographic"]},"tier":{"type":"string","enum":["target","broader","general","global"]}}}}}},"GroundingDistribution":{"type":"object","required":["name","distribution"],"properties":{"name":{"type":"string"},"translations":{"type":"object","description":"Read-only presentation, attached on read for the caller's locale (`x-locale` header or `aox-locale` cookie; default `en`): `{ [locale]: { name?, displayHeading?, segments?: { [originalLabel]: string } } }` with the friendly label a profile shows (a survey question as the attribute it measures, e.g. \"Openness to new cuisines\"; an awkward answer as a profile value). Only wording that differs from the original is present. `name` and each segment `label` stay the identity; never send this back.","additionalProperties":{"type":"object"}},"dimension":{"type":"string","enum":["age","gender","income","life_stage","representation","education","employment_status","marital_status","household_size","household_income","geography","occupation","industry","gender_identity","source_sex","nationality","visual_presentation","duration_years","none"],"description":"Language-independent personal dimension the distribution measures. Allocation reads it, with each segment's canonical, to keep every member's combination plausible."},"userEdit":{"type":"object","description":"Read-only record of what the Audience's owner changed on this chart, layered on its evidence (which stays as research found it): `kind` is `shares` (target shares set via `cohortAllocation.targetOverrides` or a rework instruction), `excluded_segment` (values removed; they stay in `reviewDistributions` with their evidence), `excluded_chart` (the chart was removed) or `user_defined` (the owner made the chart). `userShares` are the shares the owner set, `evidenceShares` the chart's evidence shares, `excludedSegments` the removed values; `instruction`, `revision` and `editedAt` say where and when. Members whose value an edit decided carry profile basis `user_target`, with the evidence share in the reason.","required":["kind","evidenceShares"],"properties":{"kind":{"type":"string","enum":["shares","excluded_segment","excluded_chart","user_defined"]},"userShares":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"pct":{"type":"number"}}}},"evidenceShares":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"pct":{"type":"number"}}}},"excludedSegments":{"type":"array","items":{"type":"string"}},"instruction":{"type":"string"},"revision":{"type":"integer"},"editedAt":{"type":"string","format":"date-time"}}},"durationStart":{"type":"object","nullable":true,"description":"duration_years only: the earliest age at which the counted time can begin for this audience, with its evidence. No member is given more years than its age minus this allows.","required":["minimumAge","evidence"],"properties":{"minimumAge":{"type":"integer","minimum":0,"maximum":80},"evidence":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["source","definitional"]},"sourceIdx":{"type":"integer","minimum":0},"quote":{"type":"string"},"justification":{"type":"string"}}}}},"segmentAgeBounds":{"type":"array","nullable":true,"description":"Ages outside which no member of this audience can be in a segment (e.g. the earliest age an occupation's training allows), with evidence. Allocation keeps every member inside its segments' ages without moving a share.","items":{"type":"object","required":["segment","evidence"],"properties":{"segment":{"type":"string"},"minAge":{"type":"integer","minimum":0,"maximum":110},"maxAge":{"type":"integer","minimum":0,"maximum":110},"evidence":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["source","definitional"]},"sourceIdx":{"type":"integer","minimum":0},"quote":{"type":"string"},"justification":{"type":"string"}}}}}},"distribution":{"type":"array","items":{"type":"object","required":["label","pct","sourceIdx"],"properties":{"label":{"type":"string"},"pct":{"type":"number","minimum":0,"maximum":100},"sourceIdx":{"type":"integer","minimum":0},"canonical":{"type":"string","description":"Language-independent value for the dimension, e.g. \"employment_full_time\", \"18-24\", or for duration_years a whole-year range like \"6-10\", \"<5\", \"30+\"."},"review":{"type":"object","properties":{"status":{"type":"string","enum":["included","excluded_by_source","conditional","unweighted"]},"evidence":{"type":"string","enum":["target","observed","candidate"]},"reason":{"type":"string"},"sourceFile":{"type":"string"}}}}}},"tier":{"type":"string","enum":["target","broader","general","global"]},"segmentRelations":{"type":"array","nullable":true,"description":"Evidence-backed relations from one of this distribution's segments to segments of another distribution of the same audience. subset: every member in segment is in one of targetSegments. excludes: no member in segment is in any of targetSegments. Enforced by cohort allocation and reported in allocationAudit.segmentRelations.","items":{"type":"object","required":["type","segment","targetDistribution","targetSegments","evidence"],"properties":{"type":{"type":"string","enum":["subset","excludes"]},"segment":{"type":"string"},"targetDistribution":{"type":"string"},"targetSegments":{"type":"array","items":{"type":"string"}},"evidence":{"type":"object","required":["kind"],"properties":{"kind":{"type":"string","enum":["source","definitional"]},"sourceIdx":{"type":"integer","minimum":0},"quote":{"type":"string"},"justification":{"type":"string"}}}}}}}},"GroundingSource":{"type":"object","required":["url","title","snippet","domain","confidence"],"properties":{"url":{"type":"string"},"title":{"type":"string"},"snippet":{"type":"string"},"domain":{"type":"string"},"publishedDate":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"tier":{"type":"string","enum":["target","broader","general","global"]},"isUserProvided":{"type":"boolean"}}},"SavedAudienceResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["id","name","mindCount","mindIds","minds","isLinkSharingEnabled","currentMemberRole"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"mindCount":{"type":"integer","minimum":0},"mindIds":{"type":"array","items":{"type":"string"}},"minds":{"type":"array","items":{"type":"object"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isPublic":{"type":"boolean"},"isSharedWithTeam":{"type":"boolean"},"isLinkSharingEnabled":{"type":"boolean"},"publicShareId":{"type":["string","null"]},"currentMemberRole":{"type":"string","enum":["owner"]}}}}},"ChatMessageRequest":{"type":"object","description":"Send `content` (or its alias `message`). Everything else is optional; `model`/`provider`, `response_format`, `tools` and `tool_choice` are validated for every chat shape but only applied on single-Mind chats.","properties":{"content":{"type":"string","minLength":1,"description":"Message text. Required unless `message` is given."},"clientRequestId":{"type":"string","format":"uuid","description":"Study chats only: idempotency key for a message queued while Minds are still training (202). A retry with the same key returns the same queued question."},"message":{"type":"string","description":"Alias for `content`. `message` wins when both are present."},"role":{"type":"string","enum":["user","system"],"default":"user","description":"`user` triggers a reply. `system` stores the text in the transcript as context for later turns and returns immediately without calling the model or counting against message caps."},"model":{"type":"string","description":"Per-message model override for single-Mind chats. Must be one of the supported IDs for `provider` (e.g. `claude-sonnet-5`, `gpt-5.4`, `gemini-3.7-flash`); retired IDs are forwarded to their replacement. Must be sent together with `provider`."},"provider":{"type":"string","enum":["anthropic","openai","google"],"description":"Provider of `model`. Must be sent together with `model`. Precedence: request override, then your team's preferred provider, then the product default."},"endUserName":{"type":["string","null"],"maxLength":120,"description":"Display name of the human end user for this turn. Omitted/empty means the Mind addresses the user neutrally (never the API-key owner's name). Aliases: `userDisplayName`, `userName`."},"response_format":{"$ref":"#/components/schemas/ChatResponseFormat"},"tools":{"type":"array","maxItems":128,"items":{"$ref":"#/components/schemas/ChatToolDefinition"},"description":"User-defined tools (function calling). Calls are returned in `tool_calls` for you to execute; they are never run server-side. Single-Mind chats only."},"tool_choice":{"$ref":"#/components/schemas/ChatToolChoice"}}},"ChatResponseFormat":{"type":"object","description":"OpenAI-style structured output request. `json_schema` runs a second extraction pass over the Mind's answer; `json_object` parses the answer as JSON (code fences are stripped). The parsed value is returned in `parsed`; `content` carries the JSON string. Extraction failures are soft: `parsed` is omitted and `content` keeps the prose.","required":["type"],"properties":{"type":{"type":"string","enum":["text","json_object","json_schema"]},"json_schema":{"type":"object","description":"Required when `type` is `json_schema`.","required":["name","schema"],"properties":{"name":{"type":"string","minLength":1},"description":{"type":"string","description":"Guides the extraction model."},"schema":{"type":"object","description":"JSON Schema for the output object.","additionalProperties":true},"strict":{"type":"boolean","default":true}}}}},"ChatToolDefinition":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"description":"Unique per request. Must not collide with the internal tool names `GET_SPARK_RAG`, `GENERATE_IMAGE`, `WEB_SEARCH`, `DISPLAY_IMAGE`, `GET_IMAGE_DETAILS`, `DOCUMENT_PROCESSING`, `ANALYZE_LINK`."},"description":{"type":"string","description":"When and how the Mind should call the tool. Drives tool selection."},"parameters":{"type":"object","description":"JSON Schema of the arguments. Omit for a no-argument tool.","additionalProperties":true},"strict":{"type":"boolean","description":"Enforce strict argument validation."}}},"ChatToolChoice":{"description":"`auto` lets the Mind decide, `required` forces at least one call, `none` disables user tools for this turn, `{ \"name\": \"…\" }` forces one specific tool. Ignored when `tools` is empty.","oneOf":[{"type":"string","enum":["auto","required","none"]},{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1}}}]},"ChatToolCall":{"type":"object","required":["id","name","arguments"],"properties":{"id":{"type":"string","description":"Echo this back as `tool_call_id` when you send the result."},"name":{"type":"string","description":"Name of one of your `tools`."},"arguments":{"type":"object","additionalProperties":true,"description":"Arguments generated by the Mind, matching the tool's `parameters` schema."}}},"ChatMessageResponse":{"oneOf":[{"$ref":"#/components/schemas/ChatMindMessageResponse"},{"$ref":"#/components/schemas/ChatMultiMindMessageResponse"},{"$ref":"#/components/schemas/ChatStudyMessageResponse"},{"$ref":"#/components/schemas/ChatSystemMessageResponse"}]},"ChatMindMessageResponse":{"type":"object","description":"Single-Mind chat reply.","required":["content","messageId"],"properties":{"content":{"type":"string","description":"The Mind's reply. A JSON string when `response_format` was `json_schema`/`json_object`; may be empty when the turn ended in `tool_calls`."},"messageId":{"type":"string","description":"ID of the persisted assistant message."},"metadata":{"$ref":"#/components/schemas/MindCompletionMetadata","description":"Source-policy and retrieval status for a knowledge-only reply."},"parsed":{"description":"Parsed structured output. Present only when `response_format` was given and extraction succeeded."},"tool_calls":{"type":"array","items":{"$ref":"#/components/schemas/ChatToolCall"},"description":"Present only when the Mind called one of your `tools`. Execute them and send the results in a follow-up message."}}},"ChatMultiMindMessageResponse":{"type":"object","description":"Multi-Mind chat reply: one entry per Mind that spoke this turn, in speaking order.","required":["messages"],"properties":{"messages":{"type":"array","minItems":1,"items":{"type":"object","required":["content","messageId","mind"],"properties":{"content":{"type":"string"},"messageId":{"type":"string"},"metadata":{"$ref":"#/components/schemas/MindCompletionMetadata","description":"Source-policy and retrieval status for this Mind."},"mind":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}}}}}}},"ChatStudyMessageResponse":{"type":"object","description":"Study chat reply: the question is classified, every ready Mind answers, and answers are aggregated per Audience.","required":["outputData"],"properties":{"outputData":{"$ref":"#/components/schemas/StudyOutputData"},"leftOutMinds":{"type":"array","description":"Present when Minds of the Audience are still being prepared (their last training attempt failed past the automatic recovery budget): the Study answered without them (at least one Mind and at least half of the Minds it asks still answer) and they are retrained in the background.","items":{"type":"object","required":["mindId","name","audienceId"],"properties":{"mindId":{"type":"string","format":"uuid"},"name":{"type":"string"},"audienceId":{"type":"string","format":"uuid"}}}}}},"ChatSystemMessageResponse":{"type":"object","description":"Returned for `role: \"system\"`; nothing was generated.","required":["messageId","role"],"properties":{"messageId":{"type":"string"},"role":{"type":"string","enum":["system"]}}},"ChatStudyMindsNotReadyError":{"type":"object","required":["statusCode","statusMessage","data"],"properties":{"statusCode":{"type":"integer","enum":[409]},"statusMessage":{"type":"string"},"data":{"type":"object","required":["code","studyId","notReadyCount","failedCount","trainingCount","notReady"],"properties":{"code":{"type":"string","enum":["PANEL_MINDS_NOT_READY"]},"cause":{"type":"string","enum":["minds_training","no_mind_can_answer"],"description":"`no_mind_can_answer`: no Mind can answer and none can be retrained automatically. `minds_training` is no longer returned here (a Study chat queues while Minds train); kept for older clients."},"studyId":{"type":"string","format":"uuid","description":"The chat ID."},"notReadyCount":{"type":"integer"},"failedCount":{"type":"integer","description":"Minds whose last training attempt failed past the automatic recovery budget. The Study runs without them when enough others answer; they are retrained automatically. Their `notReady` entries report `trainingStatus: queued`."},"trainingCount":{"type":"integer","description":"Minds still training; poll `GET /v1/minds/{mindId}/training`."},"notReady":{"type":"array","items":{"type":"object","required":["mindId","name","audienceId","trainingStatus"],"properties":{"mindId":{"type":"string","format":"uuid"},"name":{"type":"string"},"audienceId":{"type":"string","format":"uuid"},"trainingStatus":{"type":"string","enum":["queued","running","failed"]}}}}}}}},"ChatCreateRequest":{"type":"object","description":"Exactly one of `mindId`, `mindIds` or `audienceIds` selects the chat shape. `audienceIds` wins when present; otherwise `mindIds` wins over `mindId`.","properties":{"responseThread":{"type":"object","additionalProperties":false,"required":["studyId","messageId"],"description":"Continue this Mind’s exact Study response with its prior context and assets. Requires one Mind. Repeated creation resumes the existing thread (200).","properties":{"studyId":{"type":"string","format":"uuid"},"messageId":{"type":"string"}}},"name":{"type":"string","description":"Display name. Defaults to \"API Chat\" for Mind chats and \"API Study\" for Study chats."},"description":{"type":"string","description":"Optional free-text description."},"mindId":{"type":"string","format":"uuid","description":"Single Mind to chat with 1:1."},"mindIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Two or more Minds for a moderated multi-Mind conversation (duplicates are ignored). A single-element array behaves like `mindId`."},"audienceIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Audiences to attach to a Study chat. Every message fans out to all Minds in these Audiences."}}},"ChatCreated":{"type":"object","required":["id","name","createdAt","minds"],"properties":{"id":{"type":"string","format":"uuid","description":"Chat ID for `POST /v1/chats/{chatId}/messages` and `DELETE /v1/chats/{chatId}`."},"name":{"type":"string"},"description":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"minds":{"type":"array","items":{"$ref":"#/components/schemas/StudyMind"},"description":"Minds assigned to the chat. One entry for a 1:1 chat, several for a multi-Mind chat."}}},"ChatStudyCreated":{"type":"object","required":["id","name","type","audiences","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"type":{"type":"string","enum":["study"]},"audiences":{"type":"array","items":{"$ref":"#/components/schemas/ChatAudienceSummary"}},"createdAt":{"type":"string","format":"date-time"}}},"ChatAudienceSummary":{"type":"object","required":["id","name","mindCount"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"mindCount":{"type":"integer","minimum":0,"description":"Number of Minds in the Audience at creation time."}}},"ChatPlanLimitError":{"type":"object","description":"Shape of every 403 plan-limit refusal on the Chat endpoints. `data.code` is always `PLAN_LIMIT`; `limitType` says which cap was hit.","required":["statusCode","statusMessage","data"],"properties":{"statusCode":{"type":"integer","enum":[403]},"statusMessage":{"type":"string","description":"Human-readable wall copy, e.g. `Free plan limit reached` or `Free plan monthly synthetic-response limit reached. Upgrade your plan for more responses.`"},"data":{"type":"object","required":["code","limitType","currentPlan","limit"],"properties":{"code":{"type":"string","enum":["PLAN_LIMIT"]},"limitType":{"type":"string","enum":["flows","messages","responses","audienceMembers"],"description":"`flows`: started-Study cap. `messages`: per-chat user-message cap. `responses`: monthly synthetic-response allowance. `audienceMembers`: per-Audience member cap."},"currentPlan":{"type":"string","description":"Plan slug, e.g. `free`, `premium`, `team`."},"limit":{"type":"integer"},"current":{"type":"integer","description":"Usage against the cap, when known."},"requested":{"type":"integer","description":"Units this request needed (response metering only)."},"periodEnd":{"type":"string","format":"date-time","description":"When the monthly response allowance resets (response metering only)."},"context":{"type":"string","enum":["chatCreation","studyCreation","sharedStudyUsage","sharedMindUsage"],"description":"Which surface hit the wall, when the gate knows it."},"source":{"type":"string","description":"Usage-metering source tag, e.g. `api_v1`."},"isTrialing":{"type":"boolean"},"audienceId":{"type":"string","format":"uuid","description":"Offending Audience (`audienceMembers` only)."}}}}},"MindDetail":{"type":"object","required":["id","name","description","type","tags","profileDetails","filterAttributes","isPublic","isLinkSharingEnabled","knowledgeItemCount","readyToChat","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["creative","expert","user"]},"discipline":{"type":["string","null"]},"systemPrompt":{"type":"string","description":"Full generated system prompt, present only for owners and explicit Mind, shared-team, or private-Audience collaborators."},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"],"description":"Persisted source policy, present only when systemPrompt inspection is authorized."},"tags":{"type":"array","items":{"type":"string"}},"profileDetails":{"$ref":"#/components/schemas/MindProfileDetails"},"filterAttributes":{"type":"array","maxItems":7,"description":"The Mind's filter attributes (perspective, industry, role, country as ISO 3166-1 alpha-2, companySize, technology, businessModel), in that order. Only attributes with a stored value are listed; an empty array means none are recorded. Use them to narrow an Audience with `GET /audiences/{audienceId}/filter-attributes`.","items":{"type":"object","required":["key","values"],"properties":{"key":{"type":"string","enum":["perspective","industry","role","country","companySize","technology","businessModel"]},"values":{"type":"array","minItems":1,"maxItems":25,"items":{"type":"string","maxLength":120}}}}},"isPublic":{"type":"boolean"},"isLinkSharingEnabled":{"type":"boolean"},"publicShareId":{"type":["string","null"],"format":"uuid","description":"Public share token (present only when link sharing is enabled)."},"profileImageUrl":{"type":["string","null"],"format":"uri"},"phoneNumber":{"type":["string","null"]},"clonedVoiceStatus":{"type":["string","null"],"description":"Voice cloning status; null if not cloned."},"profitSplitOptIn":{"type":"boolean"},"knowledgeItemCount":{"type":"integer","description":"Number of portfolio/knowledge items attached."},"trainingStatus":{"type":["string","null"],"enum":["queued","running","completed","failed",null],"description":"Current training lifecycle state, from the same authority as GET /v1/minds/{id}/training. A failed training attempt is retried automatically until the Mind is ready, so it reports `queued`. Only a Mind without a system prompt reports `failed`, until it is retrained or its prompt is regenerated. Poll GET /v1/minds/{id}/training for full detail."},"readyToChat":{"type":"boolean","description":"True when the Mind can answer: its training has completed, or it keeps answering with its current version while an update trains. A mind's id exists before it is ready."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"MindProfileDetails":{"type":"object","description":"The Mind's stored cohort profile. `defaults` always lists the eight default attributes in this order (age, gender, geography, employment_status, occupation, income, education, life_stage); an empty `values` array means not known. `attributes` lists every other stored attribute in stored order. Nothing is inferred from the persona text.","required":["defaults","attributes"],"properties":{"defaults":{"type":"array","items":{"type":"object","required":["dimension","values"],"properties":{"dimension":{"type":"string","enum":["age","gender","geography","employment_status","occupation","income","education","life_stage"]},"values":{"type":"array","description":"One entry per stored value; several values are listed separately, never joined.","items":{"$ref":"#/components/schemas/MindProfileAttribute"}}}}},"attributes":{"type":"array","items":{"$ref":"#/components/schemas/MindProfileAttribute"}}}},"MindProfileAttribute":{"type":"object","required":["label","value","dimension","state","basis"],"properties":{"label":{"type":"string","description":"The stored distribution name."},"value":{"type":["string","null"],"description":"The stored value; null when the profile records the attribute without one (see state)."},"dimension":{"type":["string","null"],"description":"The shared attribute the value belongs to, or null."},"canonical":{"type":"string","description":"The value in the shared vocabulary, present only when the stored wording is that value (or an age band)."},"state":{"type":"string","enum":["assigned","unknown","not_applicable","not_asked","missing","refused"]},"basis":{"type":"string","enum":["user_target","internal_target","observed","public_evidence","modeled","unknown"],"description":"`modeled` is an assumption without a source."},"reason":{"type":"string","description":"The stored explanation of the basis."},"options":{"type":"array","items":{"type":"string"},"description":"Present on the options of one multi-select question shown as one attribute: `label` is the question and `value` lists these selected options, each in its stored wording."},"translations":{"type":"object","description":"Read-only presentation for the caller's locale (`x-locale` header or `aox-locale` cookie; default `en`): `{ [locale]: { label?, value? } }` with the friendly label a profile shows (a survey question as the attribute it measures, e.g. \"Openness to new cuisines\"; an awkward answer as a profile value). Only wording that differs from the stored `label`/`value` is present; those stay the identity.","additionalProperties":{"type":"object","properties":{"label":{"type":"string"},"value":{"type":"string"}}}},"figure":{"type":"object","description":"A specific figure inside the stored segment: the exact age in an age band, or an amount derived inside a bracket (approximate).","required":["value","approximate"],"properties":{"value":{"type":"number"},"unit":{"type":"string"},"unitPosition":{"type":"string","enum":["before","after"]},"approximate":{"type":"boolean"}}}}},"UpdateMindRequest":{"type":"object","description":"All fields are optional, but at least one must be present. Fields of the wrong type are ignored rather than rejected.","properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Display name (trimmed; 2-100 characters after trimming)."},"description":{"type":"string","description":"Short summary of the Mind (trimmed)."},"type":{"type":"string","enum":["creative","expert","user"],"description":"Mind archetype. Case-insensitive; aliases `artist` -> creative and `client` / `consumer` -> user; any other value becomes `creative`."},"discipline":{"type":"string","description":"Area of expertise. An empty string clears it (stored as null)."},"systemPrompt":{"type":"string","description":"Replace the full system prompt verbatim (not trimmed). Use `POST /v1/minds/{mindId}/regenerate-prompt` to rebuild it from the knowledge base instead."},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"],"description":"Persisted answer policy. `knowledge_only` always retrieves processed Mind knowledge and fails closed when it cannot support the answer; a request-level setting can never downgrade it. In a Study it still reads the stimulus a question is asked about (attached files, images, links), never as a source of facts. Empty string or null resets to `auto`."},"tags":{"type":"array","items":{"type":"string"},"maxItems":20,"description":"Replaces the tag list. Entries are trimmed, non-string and empty entries are dropped, and only the first 20 are kept."},"isPublic":{"type":"boolean","deprecated":true,"description":"Accepted for backward compatibility but always stored as false. Individual Minds cannot be made public; share an Audience instead."},"isLinkSharingEnabled":{"type":"boolean","description":"true keeps or generates a `publicShareId` so the Mind is readable via its share link; false clears it."},"isSharedWithTeam":{"type":"boolean","description":"Owner or Mind admin. true lets every current and future member of the owner's team open and chat with the Mind; it sends no invitation or notification. false removes that access at once. Sharing requires the owner to be in a team (400 `TEAM_REQUIRED`); anyone else gets 403 `TEAM_SHARE_OWNER_ONLY`."},"profileImageUrl":{"type":"string","format":"uri","description":"Avatar URL stored as given (not downloaded or re-hosted). An empty string clears the image."}}},"MindCompletionRequest":{"type":"object","properties":{"messages":{"type":"array","maxItems":100,"description":"Conversation in chronological order, ending with a `user` message or the results of prior assistant tool calls. Omit or send `[]` for the greeting bootstrap. With `sourcePolicy: \"knowledge_only\"` only the last `user` message is sent to the model.","items":{"$ref":"#/components/schemas/MindCompletionMessage"}},"responseMode":{"type":"string","enum":["sync","stream"],"default":"sync","description":"`sync` buffers the whole reply into one JSON response. `stream` answers with `text/event-stream` and delivers the same payload in a terminal `result` frame; use it whenever generation may exceed ~60 s (web search, large attachments)."},"model":{"type":"string","description":"Model override, e.g. `claude-sonnet-5-5`, `gpt-6.1-sol`, `gpt-6-luna`, `gemini-3.8-flash`. Provider is auto-detected from the `claude-`, `gemini-`, `gpt-`/`o1`/`o3`/`o4`/`chatgpt-` prefixes; retired IDs are forwarded to their replacement. Without an override the team's preferred provider (if any) or the product default is used."},"modelConnection":{"type":"object","additionalProperties":false,"required":["id","revision"],"properties":{"id":{"type":"string","format":"uuid"},"revision":{"type":"integer","minimum":1}},"description":"Explicit verified team connection. Cannot be combined with model/provider. Requires streaming, and tools/structured capabilities when used. Errors never fall back to a native model."},"provider":{"type":"string","enum":["openai","anthropic","google"],"description":"Provider of `model`. Required only when the provider cannot be auto-detected from the model name."},"language":{"type":"string","enum":["en","es","fr","de","zh","tr","ar","ja","ko"],"description":"Reply language hint. Falls back to the `x-locale` header, then `en`. Strong personas may still answer in their native language."},"endUserName":{"type":["string","null"],"description":"Display name of the human end user, normalized and truncated to 120 characters. Omitted/empty means the Mind addresses the user neutrally and never infers the API-key owner's name. Aliases: `userDisplayName`, `userName`."},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only","request_only"],"default":"auto","description":"`auto` lets the Mind use its knowledge, web search, link analysis and attachments. `knowledge_only` is fail-closed: it retrieves the Mind's processed knowledge for the last user message, disables every internal and user tool, rejects attachments and media content parts (including tool results), and answers from persona only when nothing relevant is found (recorded in `metadata.knowledgeRetrieval.status: \"fallback\"`). A Mind saved with `knowledge_only` can never be downgraded per request. `request_only` is accepted for parity with Study runs and behaves like `auto` here."},"citationMarkers":{"type":"string","enum":["inline","none"],"default":"inline","description":"`inline` leaves `[[CITE:n]]` markers (0-based indexes into `metadata.ragCitations`) after grounded claims in `content`. `none` strips them; `metadata.ragCitations` still lists the sources."},"response_format":{"$ref":"#/components/schemas/ChatResponseFormat"},"tools":{"type":"array","maxItems":128,"items":{"$ref":"#/components/schemas/ChatToolDefinition"},"description":"User-defined tools. Calls are returned in `tool_calls`; execute them yourself and send the result back as a `tool` message. Ignored with `sourcePolicy: \"knowledge_only\"`."},"tool_choice":{"$ref":"#/components/schemas/ChatToolChoice"},"parallel_tool_calls":{"type":"boolean","default":true,"description":"Accepted for OpenAI compatibility. Advisory only: the runtime does not currently constrain how many tool calls a turn may contain."},"participants":{"type":"array","maxItems":100,"items":{"type":"string"},"description":"Names (at most 200 characters each) of other participants when the Mind is one voice in a wider conversation. When non-empty the Mind answers in multi-participant mode instead of 1:1 interview mode."}}},"MindCompletionMessage":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["user","assistant","tool","system"]},"content":{"type":["string","array"],"description":"Required for every role. User strings must be non-empty (whitespace-only returns 400); assistant strings may be empty. Structured content-part arrays accept inline media and HTTP(S) URLs, but not provider options, provider-owned file/item references, custom provider parts, claimed provider execution or SDK approval state. Tool results must use the tool role; assistant tool-result parts are provider-owned state and are rejected. Tool strings are paired with tool_call_id and the matching earlier assistant call; malformed or unmatched tool history returns 400.","oneOf":[{"type":"string"},{"type":"array","maxItems":128,"items":{"type":"object","additionalProperties":true}}]},"tool_calls":{"type":"array","items":{"$ref":"#/components/schemas/ChatToolCall"},"description":"On `assistant` messages: the tool calls the Mind made in that turn, echoed back verbatim."},"tool_call_id":{"type":"string","description":"On `tool` messages: the `id` of the call this result answers. `content` is the tool result (typically a JSON string)."},"metadata":{"type":"object","description":"Per-message metadata. Only `attachedFiles` is read.","properties":{"attachedFiles":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/MindCompletionAttachment"},"description":"Files, images or web pages to process (PDF, DOCX, TXT/MD, CSV/XLSX, PNG/JPG/WEBP, HTML). Processed in parallel (30 s per file) before the Mind sees the message; the extracted content is appended to the last user message but never persisted. At most 100 attachments across the whole request before deduplication. Attachments are deduplicated by `url` across the whole history. Not allowed with `sourcePolicy: \"knowledge_only\"`."}}}}},"MindCompletionAttachment":{"type":"object","description":"Provide either `url` or `path`, not both. Files without a resolvable `url` are skipped.","properties":{"url":{"type":"string","format":"uri","description":"Public HTTP(S) URL of the file or web page."},"path":{"type":"string","description":"Storage path of an authorized upload. Renewal requires ownership, a valid chat-file signature or shared Study context access; an arbitrary path does not grant file access."},"name":{"type":"string","description":"Display name shown to the Mind."},"type":{"type":"string","description":"MIME type, e.g. `application/pdf`, `image/png`."},"description":{"type":"string"},"transcription":{"type":"string","description":"Pre-transcribed audio/video content."}}},"MindCompletionResponse":{"type":"object","required":["messageId","content"],"properties":{"messageId":{"type":"string","description":"Opaque per-call ID (`msg_` + 32 hex chars). Nothing is persisted; use it for your own correlation."},"content":{"type":"string","description":"The Mind's reply. A JSON string when `response_format` was `json_schema`/`json_object`; empty when the turn ended in `tool_calls` or an image-only result."},"parsed":{"type":["string","number","boolean","object","array","null"],"description":"Parsed structured output. Present only when `response_format` was given and extraction succeeded."},"tool_calls":{"type":"array","items":{"$ref":"#/components/schemas/ChatToolCall"},"description":"Present only when the Mind called one of your `tools`."},"metadata":{"$ref":"#/components/schemas/MindCompletionMetadata"}}},"MindCompletionMetadata":{"type":"object","description":"Present only when at least one field applies. Internal tools (knowledge retrieval, web search, image display/generation, link analysis, document processing) surface their results here, never in `tool_calls`.","properties":{"ragCitations":{"type":"array","items":{"$ref":"#/components/schemas/MindCompletionCitation"},"description":"Verified knowledge, web, link and document sources. Inline `[[CITE:n]]` markers in `content` index into this array (0-based)."},"images":{"type":"array","items":{"$ref":"#/components/schemas/MindCompletionImage"},"description":"Images the Mind displayed or generated. URLs are absolute."},"documentAnalysis":{"type":"string","description":"Analysis text of the last processed attachment, when any."},"chatCitationProvenance":{"$ref":"#/components/schemas/StudyCitationProvenance"},"sourcePolicy":{"type":"string","enum":["knowledge_only"],"description":"Present only for a knowledge-only reply."},"knowledgeRetrieval":{"$ref":"#/components/schemas/MindCompletionKnowledgeRetrieval"},"answerProvenance":{"$ref":"#/components/schemas/MindCompletionAnswerProvenance"}}},"MindCompletionCitation":{"type":"object","required":["id","displaySource"],"properties":{"id":{"type":"string"},"displaySource":{"type":"string","description":"Human-readable source name, file name or URL host."},"rawLink":{"type":"string","format":"uri"},"title":{"type":"string"},"snippet":{"type":"string"},"similarity":{"type":"number","minimum":0,"maximum":1,"description":"Relevance score for knowledge and web sources."},"sourceType":{"type":"string","enum":["mind_knowledge","web","link","document"]}}},"MindCompletionImage":{"type":"object","required":["id","url","filename","description","source"],"properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"filename":{"type":"string"},"description":{"type":"string"},"source":{"type":"string","description":"`generated` for AI-generated images, otherwise where the displayed image came from (e.g. `memory`)."},"path":{"type":"string"},"provider":{"type":"string","description":"Image generation provider (generated images only)."},"size":{"type":"string","description":"e.g. `1024x1024` (generated images only)."}}},"MindCompletionKnowledgeRetrieval":{"type":"object","description":"Source-safe retrieval summary for `sourcePolicy: \"knowledge_only\"`. Titles only; storage paths and raw file contents are never returned.","required":["status","retrievalAttempted","chunksFound","sourceCount","sources"],"properties":{"status":{"type":"string","enum":["grounded","fallback"],"description":"`grounded` when relevant knowledge chunks were used; `fallback` when none matched and the Mind answered from persona/cohort profile only."},"retrievalAttempted":{"type":"boolean","description":"False when the request had no user question to retrieve for."},"chunksFound":{"type":"integer","minimum":0,"description":"Chunks used for this answer (not the Mind's total embedding count)."},"sourceCount":{"type":"integer","minimum":0},"sources":{"type":"array","items":{"type":"object","required":["title","sourceType"],"properties":{"title":{"type":"string"},"sourceType":{"type":"string","enum":["mind_knowledge"]}}}}}},"MindCompletionAnswerProvenance":{"type":"object","description":"Answer-level origin recorded on every reply. Exact claim citations (`ragCitations` + `chatCitationProvenance`) take precedence when present.","required":["origin","sourcePolicy","retrievalAttempted","retrievalChunksFound","evidenceSourceTypes","fallbackStatus","unsupported","recordedAt","verifier"],"properties":{"origin":{"type":"string","enum":["cited_sources","mind_knowledge","request_evidence","mind_personality","unsupported"]},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only","request_only"]},"retrievalAttempted":{"type":"boolean"},"retrievalChunksFound":{"type":"integer","minimum":0},"evidenceSourceTypes":{"type":"array","items":{"type":"string","enum":["mind_knowledge","web","request_evidence","mind_personality"]}},"fallbackStatus":{"type":"string","enum":["grounded","persona_profile","uncertainty_required"]},"unsupported":{"type":"boolean","description":"True when a factual question could not be grounded; the Mind was instructed to express uncertainty."},"recordedAt":{"type":"string","format":"date-time"},"verifier":{"type":"string","enum":["single-mind-answer-provenance-v1"]}}},"MindCompletionNotReadyError":{"type":"object","required":["statusCode","statusMessage","data"],"properties":{"statusCode":{"type":"integer","enum":[409]},"statusMessage":{"type":"string","enum":["This Mind is still being prepared","This Mind has no system prompt yet; regenerate its prompt before it can chat"]},"data":{"type":"object","required":["code","mindId","trainingStatus"],"properties":{"code":{"type":"string","enum":["SPARK_NOT_READY"]},"mindId":{"type":"string","format":"uuid"},"trainingStatus":{"type":"string","enum":["queued","running","failed"]}}}}},"MindCompletionSseEvent":{"type":"object","oneOf":[{"$ref":"#/components/schemas/MindCompletionStartEvent"},{"$ref":"#/components/schemas/MindCompletionResponse"},{"$ref":"#/components/schemas/MindCompletionErrorEvent"},{"$ref":"#/components/schemas/MindCompletionDoneEvent"}],"description":"`data` payloads by frame: `start` → MindCompletionStartEvent, `result` → MindCompletionResponse, `error` → MindCompletionErrorEvent, `done` → MindCompletionDoneEvent. Lines starting with `:` are heartbeats and carry no data."},"MindCompletionStartEvent":{"type":"object","required":["type","timestamp"],"properties":{"type":{"type":"string","enum":["start"]},"timestamp":{"type":"integer","description":"Unix epoch milliseconds when generation began."}}},"MindCompletionErrorEvent":{"type":"object","description":"Sent instead of `result` when the completion failed after the stream opened. `status` is the HTTP status the same request would have received in `sync` mode.","required":["type","status","message"],"properties":{"type":{"type":"string","enum":["error"]},"status":{"type":"integer","description":"e.g. 400, 401, 403, 404, 409, 429, 500, 503."},"message":{"type":"string","description":"Public client-error message, or generic Completion failed for server/provider failures."},"errorType":{"type":"string","enum":["unsupported_model_capability","model_not_found","invalid_prompt","ai_generation_error"],"description":"Optional stable public error code."}}},"MindCompletionDoneEvent":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["done"]}}},"MindExportStatusResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["idle","queued","processing","completed","failed"],"description":"`idle` also covers an unknown or mismatched `jobId` (the job does not belong to this Mind, format, and locale)."},"progress":{"type":"number","minimum":0,"maximum":100,"description":"Present for `queued` / `processing`."},"error":{"type":"string","description":"Present for `failed`."},"kind":{"type":"string","enum":["persona_profile"],"description":"Present for `completed`."},"format":{"type":"string","enum":["pdf","md","docx","pptx"],"description":"Present for `completed`."},"filename":{"type":"string","description":"Present for `completed`."},"mimeType":{"type":"string","description":"Present for `completed`: `application/pdf`, `text/markdown;charset=utf-8`, or the docx / pptx OpenXML MIME type."},"generatedAt":{"type":["string","null"],"format":"date-time","description":"Present for `completed`."},"downloadUrl":{"type":"string","description":"Present for `completed`: relative path to `GET /v1/minds/{mindId}/export-download` for this artifact."},"content":{"type":"string","description":"Inline UTF-8 markdown; present for completed `md` exports unless `metadata=1`."},"contentBase64":{"type":"string","description":"Inline base64 file bytes; present for completed `pdf` / `docx` / `pptx` exports unless `metadata=1`."}}}}},"KnowledgeItemProcessing":{"type":"object","description":"Durable background-processing state recorded on the item. `status` is the ingestion lifecycle; poll the item `statusUrl` for embedding/pattern counts and the `readyForRetrieval` gate. Only public lifecycle fields are returned. Worker diagnostics and arbitrary metadata are omitted.","required":["status"],"properties":{"status":{"type":"string","enum":["queued","running","completed","failed","unknown"],"description":"Ingestion lifecycle state."},"regeneratePrompt":{"type":"boolean","description":"Whether the Mind system prompt is regenerated once embeddings and patterns finish successfully."},"error":{"type":"string","description":"Generic failure message when `status` is `failed`; internal diagnostics are not returned."},"startedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time"},"failedAt":{"type":"string","format":"date-time"},"embeddingsCreated":{"type":"integer","minimum":0},"patternsCreated":{"type":"integer","minimum":0},"promptRegenerated":{"type":"boolean","description":"Whether the optional prompt-regeneration step completed. Present only when recorded."}},"additionalProperties":false},"KnowledgeItem":{"type":"object","description":"A knowledge source attached to a Mind. Exactly one of `link` or `filePath` is set for user-added items; auto-collected sources can also be link-based.","required":["id","description","link","filePath","isWatched","category","relevance","evidence","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"description":{"type":"string","description":"Human-readable description supplied when the item was added."},"link":{"type":["string","null"],"format":"uri","description":"Source URL for link-based items; null for uploaded files."},"filePath":{"type":["string","null"],"description":"Storage path of the uploaded file (`portfolio/{userId}/{timestamp}_{name}`); null for link-based items."},"isWatched":{"type":"boolean","description":"True when a link item is watched for weekly content changes (managed in the product UI; links only)."},"category":{"type":"string","enum":["lived_experience","social_context","category_behaviour","product_context","education","employment","household_context","economic_context","local_context","business_operations","business_market","business_regulation","business_finance","business_workforce","uncategorized"],"description":"Knowledge category: the search goal the source was collected for, else the category read once from its content. `uncategorized` until either exists, or when the content has no defensible subject."},"relevance":{"type":["number","null"],"minimum":0,"maximum":1,"description":"How useful the source is for the stakeholder role or search topic it was reviewed for (0–1): the content review's score, read once from its content and shared by every Mind reviewed for the same role or topic, not a judgement about this individual Mind. Null until reviewed. Scales the source's height on the knowledge sphere."},"evidence":{"type":["string","null"],"enum":["primary_data","first_hand","analysis","reporting","opinion","marketing","reference","other",null],"description":"What kind of evidence the source is, read once from its content; null until assessed."},"processing":{"$ref":"#/components/schemas/KnowledgeItemProcessing","description":"Absent for legacy items without recorded processing metadata."},"statusUrl":{"type":"string","description":"Relative path of `GET /api/v1/minds/{mindId}/knowledge/{itemId}/status` for this item."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"AddKnowledgeLinkRequest":{"type":"object","title":"Link","required":["link","description"],"properties":{"link":{"type":"string","format":"uri","description":"URL of a web page, YouTube video, or research paper. Note the field is `link`, not `url`."},"description":{"type":"string","description":"Description of the content."},"regeneratePrompt":{"type":"boolean","default":false,"description":"Regenerate the Mind system prompt once ingestion succeeds."}}},"AddKnowledgeRemoteFileRequest":{"type":"object","title":"Remote or workspace file","required":["file","description"],"properties":{"file":{"type":"object","required":["name","url"],"properties":{"name":{"type":"string","description":"Filename including extension; used to derive the storage name and content type."},"url":{"type":"string","format":"uri","description":"Public/signed HTTPS URL, or an authorized Minds workspace upload URL. Workspace uploads require file ownership, a valid chat-file signature, or shared context access through the uploader’s Study; editing the Mind alone is insufficient. Private-network and unsafe URLs are rejected."},"type":{"type":"string","description":"MIME type hint. Falls back to the fetched response `Content-Type`."}}},"description":{"type":"string","description":"Description of the content."},"regeneratePrompt":{"type":"boolean","default":false,"description":"Regenerate the Mind system prompt once ingestion succeeds."}}},"AddKnowledgeKeywordsRequest":{"type":"object","title":"Keyword web search","required":["keywords"],"properties":{"keywords":{"type":"array","minItems":1,"maxItems":15,"items":{"type":"string"},"description":"Search topics. Trimmed, de-duplicated, and capped at 15 (extras are silently dropped). Must contain at least one non-empty string."},"regeneratePrompt":{"type":"boolean","default":true,"description":"Regenerate the Mind system prompt after the collected content is processed."}}},"KnowledgeItemAccepted":{"type":"object","title":"Knowledge item accepted","description":"Created item for file and link modes. `filePath` is present for uploads, `link` for URLs; `isWatched`/`updatedAt` are not included here (see the list endpoint).","required":["id","description","createdAt","processing","statusUrl"],"properties":{"id":{"type":"string","format":"uuid"},"description":{"type":"string"},"link":{"type":"string","format":"uri","description":"Present for link mode only."},"filePath":{"type":"string","description":"Present for file modes only: `portfolio/{userId}/{uuid}_{sanitizedName}`."},"createdAt":{"type":"string","format":"date-time"},"processing":{"$ref":"#/components/schemas/KnowledgeItemProcessing","description":"Always `{ status: \"queued\", regeneratePrompt }` at creation: the full reading (tables and charts for files) runs in the background."},"searchable":{"type":"boolean","description":"File modes only. True when the file's text was already indexed before the response, so the Mind can use it at once; its tables and charts are added when `processing` completes. False when the text could not be read in the request (pictures, recordings): poll `statusUrl` until `readyForRetrieval` is true."},"statusUrl":{"type":"string","description":"Relative path of `GET /api/v1/minds/{mindId}/knowledge/{itemId}/status`; poll until `readyForRetrieval` is true."}}},"KnowledgeEnrichmentAccepted":{"type":"object","title":"Keyword enrichment accepted","required":["mindId","keywords","queued","regeneratePrompt","message"],"properties":{"mindId":{"type":"string","format":"uuid"},"keywords":{"type":"array","items":{"type":"string"},"description":"Normalised keywords actually queued (trimmed, de-duplicated, max 15)."},"queued":{"type":"boolean","const":true},"regeneratePrompt":{"type":"boolean"},"message":{"type":"string","example":"Knowledge enrichment queued with 2 keyword(s). Web search and content processing will run in background."}}},"KnowledgePatternEvidence":{"type":"object","required":["mind"],"properties":{"mind":{"type":"string","description":"The extracted pattern text (citation/quote) supporting this sub-aspect."},"portfolioItemId":{"type":["string","null"],"format":"uuid","description":"Knowledge item the pattern was extracted from. Present only for privileged callers; null for patterns without a source item."},"createdAt":{"type":"string","format":"date-time","description":"When the pattern was extracted. Present only for privileged callers."}}},"KnowledgePatternSubAspect":{"type":"object","required":["id","name","description","occurrences","evidence"],"properties":{"id":{"type":"string","description":"Framework sub-aspect ID, or `(none)` for patterns filed directly under the aspect."},"name":{"type":"string","description":"Sub-aspect name, or `(General)` for patterns without a sub-aspect."},"description":{"type":"string","description":"Framework definition; empty string when unknown."},"occurrences":{"type":"integer","description":"Number of patterns matched to this sub-aspect."},"evidence":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgePatternEvidence"}}}},"KnowledgePatternAspect":{"type":"object","required":["id","name","description","occurrences","subAspects"],"properties":{"id":{"type":"string","description":"Framework aspect ID (e.g. `ocean-O`)."},"name":{"type":"string"},"description":{"type":"string"},"occurrences":{"type":"integer","description":"Number of patterns matched to this aspect (sum of its sub-aspects)."},"subAspects":{"type":"array","description":"Sub-aspects with at least one occurrence, sorted by occurrences descending.","items":{"$ref":"#/components/schemas/KnowledgePatternSubAspect"}}}},"KnowledgePatternFramework":{"type":"object","required":["id","name","totalOccurrences","aspects"],"properties":{"id":{"type":"string","description":"Framework ID (e.g. `ocean`, `disc`, `riasec`)."},"name":{"type":"string","description":"Framework display name (e.g. `Big Five (OCEAN)`)."},"totalOccurrences":{"type":"integer","description":"Sum of aspect occurrences within this framework."},"aspects":{"type":"array","description":"Aspects with at least one occurrence, sorted by occurrences descending.","items":{"$ref":"#/components/schemas/KnowledgePatternAspect"}}}},"MindPattern":{"type":"object","required":["id","aspect","subAspect","mind"],"properties":{"id":{"type":"integer","description":"Pattern row ID."},"aspect":{"type":"string","description":"Detected method / aspect (legacy name for the `method` column)."},"subAspect":{"type":["string","null"],"description":"Detected competency / sub-aspect (legacy name for the `competency` column)."},"mind":{"type":"string","description":"The supporting quote or insight text for this pattern."},"mindId":{"type":["string","null"],"format":"uuid","description":"Owning Mind. Full rows only."},"userId":{"type":["string","null"],"format":"uuid","description":"User who owned the source material. Full rows only."},"messageId":{"type":["string","null"],"description":"Chat message the pattern was extracted from, if any. Full rows only."},"portfolioItemId":{"type":["string","null"],"format":"uuid","description":"Knowledge item the pattern was extracted from, if any. Full rows only."},"isPredefined":{"type":"boolean","description":"Full rows only."},"isPredefinedAspect":{"type":"boolean","description":"Whether `aspect` comes from a predefined framework. Full rows only."},"isPredefinedSubAspect":{"type":"boolean","description":"Whether `subAspect` comes from a predefined framework. Full rows only."},"createdAt":{"type":"string","format":"date-time","description":"Full rows only."}}},"TrainingStatus":{"type":"object","required":["status","readyToChat"],"properties":{"status":{"type":"string","enum":["queued","running","completed","failed"],"description":"Training lifecycle state. A failed attempt is retried automatically until the mind is ready, so it reports `queued`; `failed` is reported only for a mind without a system prompt, until it is retrained or its prompt is regenerated."},"readyToChat":{"type":"boolean","description":"True when the mind can answer: training has completed, or it keeps answering with its current version while an update trains (`servingPreviousVersion`). This is the moment a mind (and an Audience whose minds all report it) is ready: chat and Studies can use it."},"beingRepaired":{"type":"boolean","description":"Present and true while the mind cannot answer yet because its last training attempt failed and it is retrained automatically (`status` is `queued`). Waiting for readiness may stop waiting for it: a Study runs without it when enough others answer."},"servingPreviousVersion":{"type":"boolean","description":"Present and true while an update of a ready mind trains: the mind keeps answering with its current version until the update lands."},"learningInBackground":{"type":"boolean","description":"True while a mind that is already `readyToChat` keeps learning from its sources in the background: a wider source collection, then a system prompt rebuilt from everything collected. Its answers can still deepen until it settles; nothing needs to wait for it."},"fullyTrained":{"type":"boolean","description":"True once the mind is `readyToChat` and its background knowledge step has settled (`learningInBackground` false). Automatic validation of a new Audience waits for every member to be fully trained."},"message":{"type":["string","null"],"description":"Human-readable progress / status message."},"startedAt":{"type":["string","null"],"format":"date-time","description":"When training started (null until running)."},"completedAt":{"type":["string","null"],"format":"date-time","description":"When training finished (completed or failed)."},"knowledgeState":{"type":["object","null"],"description":"What the mind actually knows, which is a different question from whether it can answer. Null only when the lookup itself failed, which never blocks the readiness fields. `readyToChat` flips true as soon as a profile and system prompt exist; a mind whose collection found nothing keeps one generated training-context item instead and still reports ready. Check `fallbackOnly` before running research on it.","required":["sourceCount","researchedSourceCount","embeddingCount","fallbackOnly"],"properties":{"sourceCount":{"type":"integer","description":"Knowledge items attached to the mind, including any fallback item."},"researchedSourceCount":{"type":"integer","description":"Items that are researched or user-supplied, i.e. not the generated fallback."},"embeddingCount":{"type":"integer","description":"Searchable embeddings built from those items."},"fallbackOnly":{"type":"boolean","description":"True when the mind answers from its generated profile alone, with no researched or supplied knowledge."},"fallbackReason":{"type":["string","null"],"description":"Why collection was skipped, e.g. `no_web_without_seeded_corpus`."}}},"error":{"type":["object","null"],"description":"Present only when status is `failed` (a mind without a system prompt).","required":["code","retryable"],"properties":{"code":{"type":"string","enum":["COLLECTION_FAILED","PROFILE_GEN_FAILED","TIMEOUT","INTERNAL"]},"retryable":{"type":"boolean","description":"When true, POST /v1/minds/{id}/retrain may recover the mind."}}}}},"MindSummary":{"type":"object","required":["id","name","description","type","tags","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Mind ID."},"name":{"type":"string","description":"Mind display name."},"description":{"type":"string","description":"Short summary of the Mind."},"type":{"type":"string","enum":["creative","expert","user"],"description":"Mind archetype."},"discipline":{"type":["string","null"],"description":"Area of expertise / domain."},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"],"description":"Persisted source policy for this Mind."},"tags":{"type":"array","items":{"type":"string"},"description":"User-supplied tags (max 20)."},"profileImageUrl":{"type":["string","null"],"format":"uri","description":"Avatar image; resolved to an absolute URL."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isOwner":{"type":"boolean","description":"On list responses: true for Minds the caller owns, false for Minds shared with them."}}},"Pagination":{"type":"object","required":["total","limit","offset"],"properties":{"total":{"type":"integer","description":"Total matching rows."},"limit":{"type":"integer","description":"Page size requested."},"offset":{"type":"integer","description":"Number of rows skipped."}}},"CreateMindRequest":{"type":"object","required":["name","discipline"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Mind display name."},"discipline":{"type":"string","description":"Area of expertise (e.g. \"Marketing\", \"Engineering\")."},"description":{"type":"string","description":"Short summary. Defaults to \"Created via API\"."},"mode":{"type":"string","enum":["keywords","clone","link","manual"],"default":"keywords","description":"Training mode."},"type":{"type":"string","enum":["creative","expert","user"],"default":"expert"},"keywords":{"type":"array","items":{"type":"string"},"description":"Required when `mode=keywords`."},"personaContext":{"type":"string","description":"Required when `mode=clone` (name + brief context of the person to emulate)."},"contextLink":{"type":"string","format":"uri","description":"Required when `mode=link` (URL the AI will scrape)."},"link":{"type":"string","format":"uri","description":"Deprecated alias for `contextLink`."},"tags":{"type":"array","items":{"type":"string"},"maxItems":20},"profileImageUrl":{"type":"string","format":"uri","description":"Public HTTP(S) raster avatar URL. Remote downloads are limited to 50 MiB and 30 seconds; private destinations and SVG are refused. If download or storage fails, creation retains the original URL."},"generateImage":{"type":"boolean","description":"Trigger async AI profile-image generation after creation. Defaults to true for auto-training modes; pass false to opt out."},"includeWebSearch":{"type":"boolean","default":true,"description":"Set false to skip automatic web research. For a strictly private source-only Mind, use mode=manual, upload knowledge, then regenerate the prompt."},"isRealPerson":{"type":"boolean","description":"Whether the Mind emulates a real, named person. Defaults to true for mode=clone and false otherwise. Synthetic Minds (false) get name-blind persona prompts: the name is a label, never the seed of the biography."},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"],"default":"auto","description":"Persisted source policy. knowledge_only always retrieves processed Mind knowledge and fails closed when it cannot support the answer. In a Study it still reads the stimulus a question is asked about (attached files, images, links), never as a source of facts."},"isLinkSharingEnabled":{"type":"boolean","description":"Enable link sharing; generates a `publicShareId`."},"locale":{"type":"string","description":"ISO 639-1 code for the auto-generated description language. Falls back to the user's preferredLanguage, then `en`."}}},"StudyAnalytics":{"type":"object","additionalProperties":true,"required":["studyName","totalAudiences","totalMinds","totalQuestions","totalDataPoints","questions"],"properties":{"studyName":{"type":"string"},"locale":{"type":"string","description":"Study display locale used to format values: the language of the Study's confirmed research plan (studyLocale), else the stored Study locale, else en."},"totalAudiences":{"type":"integer","minimum":0},"totalMinds":{"type":"integer","minimum":0,"description":"Total Minds across the Study's Audiences (legacy wire name)."},"totalQuestions":{"type":"integer","minimum":0},"totalDataPoints":{"type":"integer","minimum":0},"questions":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"index":{"type":"integer","minimum":1},"title":{"type":"string"},"type":{"type":"string","enum":["scale","categorical","multiselect","qualitative"]},"classification":{"$ref":"#/components/schemas/StudyQuestionClassification"},"stats":{"type":"object","additionalProperties":true}}}},"scaleQuestionRankings":{"type":"array","description":"Scale questions ranked by overall mean, only among questions that share one scale (authored points, else range) and one unit. A missing unit and a missing range each form their own audience. A question alone on its measure has no ranking position and appears in no audience. Replaces the former single scaleQuestionRanking list, which compared means on different scales and units.","items":{"type":"object","required":["scale","questions"],"properties":{"scale":{"type":"object","description":"The shared scale. Empty for open numeric questions without authored bounds.","properties":{"range":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number"}},"points":{"type":"array","items":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string"},"value":{"type":"number"}}}}}},"unit":{"$ref":"#/components/schemas/NumericUnit"},"questions":{"type":"array","minItems":2,"description":"Highest mean first.","items":{"type":"object","required":["title","mean","sigma","signalStrength"],"properties":{"title":{"type":"string"},"mean":{"type":"number"},"sigma":{"type":"number"},"signalStrength":{"type":"string","enum":["strong","moderate","weak"]}}}}}}}}},"StudyAskRequest":{"type":"object","required":["question"],"properties":{"question":{"type":"string","minLength":1,"description":"Research question to ask the study."},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"],"default":"auto","description":"knowledge_only forbids live/request sources, requires each Mind's processed knowledge, and fails closed when retrieval is empty."},"historyMode":{"type":"string","enum":["last5","followup_only","none"],"default":"none","description":"How much of each Mind's own prior answers this question carries. Defaults to none. Use last5 when a respondent's coherence across items is the deliverable."},"audienceIds":{"type":"array","description":"Optional subset of attached audience UUIDs to ask. Defaults to all audiences on the study.","items":{"type":"string","format":"uuid"}},"textAttachments":{"type":"array","description":"Pasted material the question is about (a newsletter, an email, a concept text), sent beside the question instead of inside it. Each entry is stored as a Markdown file in your uploads and processed like an entry of `attachments`; on a queued ask, respondents read the documents the run reads as material to react to. Counts toward the attachment limit. Rejected with `sourcePolicy: knowledge_only`.","items":{"type":"object","required":["text"],"additionalProperties":false,"properties":{"name":{"type":"string","maxLength":200,"description":"File name for the stored Markdown file."},"text":{"type":"string","minLength":1,"description":"The pasted material, verbatim."}}}},"attachments":{"type":"array","description":"Files or images to process once and include as context for every Mind in the Study. Workspace uploads require ownership, a valid chat-file signature or shared Study context access. Remote HTTP(S) URLs are fetched with their own access token; knowing a storage path does not authorize renewal.","items":{"$ref":"#/components/schemas/StudyAttachment"}},"links":{"type":"array","description":"Web links to fetch and summarize for context.","items":{"$ref":"#/components/schemas/StudyContextLink"}},"keywords":{"type":"array","description":"Keyword/source pairs to fetch and summarize for context.","items":{"$ref":"#/components/schemas/StudyKeywordContext"}},"model":{"type":"string","description":"Optional per-request model override. Must be sent together with `provider`."},"provider":{"type":"string","enum":["openai","anthropic","google"],"description":"Provider for the model override. Must be sent together with `model`."},"disableQuestionClassifier":{"type":"boolean","default":false,"description":"Skip automatic scale/categorical/multiselect/qualitative classification."},"responseMode":{"type":"string","enum":["stream","queued"],"description":"Use queued to persist the question and return immediately while durable workers generate the answers. Queued asks support sourcePolicy auto; use the durable runs endpoint for request_only, knowledge_only, or model connections. When omitted, the ask streams; while Minds of the Study are still training it is queued instead and answers 202 with the queued receipt (sourcePolicy auto). An explicit `stream` always streams, waiting with the stream open (up to 9 minutes) until those Minds are ready."},"responseForm":{"type":"string","enum":["concise","standard","expanded"],"description":"How long and how shaped each answer should be, for qualitative questions: `concise` one short message (5-20 words), `standard` 1-3 sentences (25-90 words), `expanded` 2-5 sentences (70-180 words). Omit to let the question decide, which is the existing behaviour. An authored form outranks the phrasing of the question, so a fixed instrument keeps its exact wording. Ignored for scale, categorical and multiselect questions, which are shaped by their answer space."},"clientRequestId":{"type":"string","format":"uuid","description":"Optional idempotency key for queued submissions."}}},"StudyAttachment":{"type":"object","properties":{"url":{"type":"string","description":"External URL for the uploaded or remote file."},"path":{"type":"string","description":"Storage path for an uploaded file."},"name":{"type":"string"},"type":{"type":"string","description":"MIME type when known."}}},"StudyContextLink":{"type":"object","properties":{"label":{"type":"string","description":"URL or display label."},"url":{"type":"string","description":"URL to fetch when separate from `label`."},"id":{"type":"string"}}},"StudyKeywordContext":{"type":"object","properties":{"label":{"type":"string","description":"Keyword or topic label."},"url":{"type":"string","description":"Optional source URL for the keyword."},"id":{"type":"string"}}},"StudyAskSseEvent":{"oneOf":[{"$ref":"#/components/schemas/StudyAskStartEvent"},{"$ref":"#/components/schemas/StudyAskClassificationEvent"},{"$ref":"#/components/schemas/StudyAskAnswerEvent"},{"$ref":"#/components/schemas/StudyAskAggregatingEvent"},{"$ref":"#/components/schemas/StudyAskResultEvent"},{"$ref":"#/components/schemas/StudyAskDoneEvent"},{"$ref":"#/components/schemas/StudyAskErrorEvent"}]},"StudyAskStartEvent":{"type":"object","required":["type","total"],"properties":{"type":{"type":"string","enum":["start"]},"total":{"type":"integer","description":"Total number of minds that will answer."}}},"StudyAskClassificationEvent":{"type":"object","required":["type","classification"],"properties":{"type":{"type":"string","enum":["classification"]},"classification":{"$ref":"#/components/schemas/StudyQuestionClassification"}}},"StudyAskAnswerEvent":{"type":"object","required":["type","mindId","mindName","audienceId","audienceName","answer"],"properties":{"type":{"type":"string","enum":["answer"]},"mindId":{"type":"string","format":"uuid"},"mindName":{"type":"string"},"discipline":{"type":["string","null"]},"profileImageUrl":{"type":["string","null"]},"audienceId":{"type":"string","format":"uuid"},"audienceName":{"type":"string"},"answer":{"type":"string"}}},"StudyAskAggregatingEvent":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["aggregating"]}}},"StudyAskResultEvent":{"type":"object","required":["type","outputData","outputType"],"properties":{"type":{"type":"string","enum":["result"]},"outputData":{"$ref":"#/components/schemas/StudyOutputData"},"outputType":{"type":"string","enum":["bar"]}}},"StudyAskDoneEvent":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["done"]}}},"StudyAskErrorEvent":{"type":"object","required":["type","statusCode","statusMessage"],"description":"Last event of a stream that failed after it opened. Carries what the HTTP error response would have: an error before the stream opens is still returned as that HTTP status.","properties":{"type":{"type":"string","enum":["error"]},"statusCode":{"type":"integer","description":"HTTP status the error corresponds to, e.g. 422 for an attachment that could not be processed."},"statusMessage":{"type":"string"},"data":{"type":"object","additionalProperties":true,"description":"Error details, e.g. `{ errorCode: \"ATTACHMENT_PROCESSING_FAILED\", fileNames: [...] }`."}}},"StudyQuestionClassification":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["scale","categorical","multiselect","qualitative"]},"scaleRange":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number"}},"unit":{"$ref":"#/components/schemas/NumericUnit"},"scalePoints":{"type":"array","description":"Authored numeric answer mapping in order: each allowed value with its literal label.","items":{"type":"object","required":["label","value"],"properties":{"label":{"type":"string"},"value":{"type":"number"}}}},"options":{"type":"array","items":{"type":"string"}},"ranked":{"type":"boolean","description":"True for a ranking question, which runs as a categorical choice over its first place plus each Mind's full order."},"responseMode":{"type":"string","enum":["everyday","standard_qualitative","deliberative_values","scale","categorical","factual_research"],"description":"Answer-depth and grounding policy, orthogonal to the structured response type."}}},"StudyOutputData":{"type":"object","required":["title","type","audiences"],"properties":{"title":{"type":"string"},"type":{"type":"string","enum":["scale","categorical","multiselect","qualitative"]},"classification":{"$ref":"#/components/schemas/StudyQuestionClassification"},"ranking":{"type":"object","description":"Present for a ranking question: each option's mean position (1 = first) and first-place count, best first.","required":["respondents","options"],"properties":{"respondents":{"type":"integer","minimum":0},"options":{"type":"array","items":{"type":"object","required":["option","meanRank","firstCount"],"properties":{"option":{"type":"string"},"meanRank":{"type":"number"},"firstCount":{"type":"integer","minimum":0}}}}}},"categoryCodebook":{"type":"array","items":{"$ref":"#/components/schemas/StudyCategoryCodebookEntry"}},"audiences":{"type":"array","deprecated":true,"description":"Deprecated alias for audiences.","items":{"$ref":"#/components/schemas/StudyOutputAudience"}}}},"StudyCategoryCodebookEntry":{"type":"object","required":["label","originalLabels","count"],"properties":{"label":{"type":"string"},"originalLabels":{"type":"array","items":{"type":"string"}},"count":{"type":"integer","minimum":0}}},"StudyOutputAudience":{"type":"object","required":["audience","value","answers"],"properties":{"audience":{"type":"string","deprecated":true,"description":"Deprecated alias for audience."},"value":{"type":"string"},"alignmentScore":{"type":"integer","minimum":0,"maximum":100},"answers":{"type":"array","items":{"$ref":"#/components/schemas/StudyOutputAnswer"}}}},"StudyOutputAnswer":{"type":"object","required":["value","persona","message"],"properties":{"value":{"type":"string"},"rawValue":{"type":"string"},"rankedValues":{"type":"array","items":{"type":"string"},"description":"Ranking questions: this Mind's full order, first place first (value is the first place)."},"persona":{"type":"string"},"discipline":{"type":["string","null"]},"message":{"type":"string","description":"The Mind's response of record. Quote renderedVerbatim when present."},"renderedVerbatim":{"type":"string","description":"Validated display wording of message, carrying the same [N] citation markers as message. Present when a validated display rewrite exists; the app, exports and MCP show it instead of message. Structured fields never change."},"imageUrl":{"type":["string","null"]},"reliabilityScore":{"type":"integer","minimum":0,"maximum":100},"citationSources":{"type":"array","description":"Claim-level sources referenced by zero-based [N] markers in message and renderedVerbatim.","items":{"$ref":"#/components/schemas/StudyCitationSource"}},"citationProvenance":{"$ref":"#/components/schemas/StudyCitationProvenance"},"answerProvenance":{"$ref":"#/components/schemas/StudyAnswerProvenance"}}},"StudyCitationSource":{"type":"object","required":["id","title","sourceType"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","format":"uri"},"domain":{"type":"string"},"sourceType":{"type":"string","enum":["mind_knowledge","web"]},"similarity":{"type":"number"}}},"StudyCitationProvenance":{"type":"object","required":["mode","status","recordedAt","verifier"],"properties":{"mode":{"type":"string","enum":["generation","retroactive"]},"status":{"type":"string","enum":["attributed","verified","partial","unavailable"]},"recordedAt":{"type":"string","format":"date-time"},"verifier":{"type":"string","enum":["study-citations-v1"]},"reason":{"type":"string","enum":["no_evidence","no_claims","timeout","error"],"description":"Only when status is unavailable: why no sources could be attributed."}}},"StudyAnswerProvenance":{"type":"object","required":["origin","sourcePolicy","retrievalAttempted","retrievalChunksFound","retrievalChunksUsed","evidenceSourceTypes","fallbackStatus","unsupported","sharedEmbeddingReuse","recordedAt","verifier"],"properties":{"origin":{"type":"string","description":"Canonical answer origin. `group_grounding` was renamed to `audience_grounding`; it is still listed so a response recorded before the rename validates.","enum":["cited_sources","mind_knowledge","mind_personality","request_evidence","audience_grounding","group_grounding","unsupported"]},"originLegacy":{"type":"string","deprecated":true,"description":"Pre-rename spelling of `origin`, present only when one exists. Switch to `origin`; this field will be removed.","enum":["group_grounding"]},"sourcePolicy":{"type":"string","enum":["auto","knowledge_only"]},"retrievalAttempted":{"type":"boolean"},"retrievalChunksFound":{"type":"integer","minimum":0},"retrievalChunksUsed":{"type":"integer","minimum":0},"evidenceSourceTypes":{"type":"array","items":{"type":"string"}},"fallbackStatus":{"type":"string","enum":["grounded","persona_profile","uncertainty_required"]},"unsupported":{"type":"boolean"},"sharedEmbeddingReuse":{"type":"boolean"},"recordedAt":{"type":"string","format":"date-time"},"verifier":{"type":"string","enum":["study-answer-provenance-v1"]}}},"StudyExportStatusResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["idle","queued","processing","completed","failed"]},"progress":{"type":"number","minimum":0,"maximum":100},"downloadUrl":{"type":"string","format":"uri"},"error":{"type":"string"},"errorCode":{"type":"string","enum":["EXPORT_FAILED"]},"generatedAt":{"type":["string","null"],"format":"date-time"},"filename":{"type":"string"},"mimeType":{"type":"string"},"kind":{"type":"string","enum":["executive_brief","full_report","raw_data"]},"format":{"type":"string","enum":["pdf","html","png","md","docx","pptx","csv","xls","sav"]},"sourceVersion":{"type":"string"}}}}},"StudyExportRequest":{"type":"object","properties":{"kind":{"type":"string","enum":["executive_brief","full_report","raw_data"],"default":"full_report"},"format":{"type":"string","enum":["pdf","md","docx","pptx","csv","xls","sav"],"default":"md"},"length":{"type":"string","enum":["short","standard","detailed"],"default":"standard"},"force":{"type":"boolean","default":false},"scheduledRunId":{"type":"string","format":"uuid"}}},"StudyExportJobResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["kind","format","jobId","status"],"properties":{"kind":{"type":"string","enum":["executive_brief","full_report","raw_data"]},"format":{"type":"string","enum":["pdf","md","docx","pptx","csv","xls","sav"]},"jobId":{"type":"string"},"status":{"type":"string","enum":["queued"]}}}}},"StudySummary":{"type":"object","required":["id","name","studyMode","createdAt","updatedAt","messageCount","audiences"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"studyMode":{"type":"string","enum":["study"],"description":"Canonical Study resource discriminator."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"messageCount":{"type":"integer","description":"Number of stored messages across all roles, including user, assistant and system messages."},"isPublic":{"type":"boolean","description":"Whether the Study is publicly accessible."},"isLinkSharingEnabled":{"type":"boolean"},"isSharedWithTeam":{"type":"boolean","description":"Whether the owner shared the Study with their team. Change it with PUT /api/v1/studies/{studyId}/sharing."},"publicShareId":{"type":["string","null"],"format":"uuid"},"audiences":{"type":"array","items":{"type":"object","required":["id","name","mindCount","minds"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"mindCount":{"type":"integer"},"minds":{"type":"array","items":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"discipline":{"type":["string","null"]},"profileImageUrl":{"type":["string","null"],"format":"uri"}}}}}}}}},"StudyMind":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"discipline":{"type":["string","null"]},"profileImageUrl":{"type":["string","null"],"format":"uri"}}},"StudyAudience":{"type":"object","required":["id","name","minds"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"minds":{"type":"array","items":{"$ref":"#/components/schemas/StudyMind"}}}},"StudyCreated":{"type":"object","required":["id","name","studyMode","createdAt","isLinkSharingEnabled","publicShareId","audiences"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"studyMode":{"type":"string","enum":["study"]},"createdAt":{"type":"string","format":"date-time"},"isLinkSharingEnabled":{"type":"boolean"},"publicShareId":{"type":["string","null"],"format":"uuid"},"audiences":{"type":"array","items":{"$ref":"#/components/schemas/StudyAudience"}}}},"StudyMessage":{"type":"object","required":["id","role","content","metadata","createdAt"],"properties":{"id":{"type":"string"},"role":{"type":"string"},"content":{"type":"string"},"metadata":{},"createdAt":{"type":"string","format":"date-time"}}},"StudyDetail":{"type":"object","required":["id","name","studyMode","createdAt","updatedAt","isLinkSharingEnabled","publicShareId","audiences","messages"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"studyMode":{"type":"string","enum":["study"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isPublic":{"type":"boolean","description":"Whether the Study is publicly accessible."},"isLinkSharingEnabled":{"type":"boolean"},"isSharedWithTeam":{"type":"boolean","description":"Whether the owner shared the Study with their team. Change it with PUT /api/v1/studies/{studyId}/sharing."},"publicShareId":{"type":["string","null"],"format":"uuid"},"audiences":{"type":"array","items":{"$ref":"#/components/schemas/StudyAudience"}},"messages":{"type":"array","items":{"$ref":"#/components/schemas/StudyMessage"}}}},"StudyDraftPayload":{"type":"object","required":["version","state"],"additionalProperties":true,"properties":{"version":{"type":"integer","enum":[1]},"state":{"type":"object","additionalProperties":true}}},"StudyDraftCreateInput":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"mode":{"type":"string","enum":["quick","custom"]},"currentStep":{"type":"string"},"payload":{"$ref":"#/components/schemas/StudyDraftPayload"},"idempotencyKey":{"type":"string"}}},"StudyDraft":{"type":"object","required":["id","userId","name","mode","currentStep","revision","status","payload","studyId","startRequestId","startLeaseExpiresAt","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"name":{"type":"string"},"mode":{"type":"string","enum":["quick","custom"]},"currentStep":{"type":"string"},"revision":{"type":"integer","minimum":1},"sourceState":{"type":"string","enum":["none","ready","required"],"description":"Server assessment on creation, saving and reopening; ready does not replace verification of the submitted rows."},"status":{"type":"string","enum":["draft","starting","consumed"]},"payload":{"$ref":"#/components/schemas/StudyDraftPayload"},"studyId":{"type":["string","null"],"format":"uuid"},"startRequestId":{"type":["string","null"],"format":"uuid"},"startLeaseExpiresAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"StudyTemplateInviteInput":{"type":"object","additionalProperties":false,"required":["emails"],"properties":{"emails":{"type":"array","minItems":1,"maxItems":20,"items":{"type":"string","format":"email","maxLength":320}}}},"StudyTemplateInvitation":{"type":"object","required":["id","email","status","expiresAt","createdAt"],"properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"status":{"type":"string","enum":["pending","accepted","cancelled","revoked"]},"expiresAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}},"StudyTemplateAccessEntry":{"type":"object","required":["id","kind","email","status"],"properties":{"id":{"type":"string","format":"uuid","description":"Invitation id for an invitation, user id for a member."},"kind":{"type":"string","enum":["invitation","member"]},"email":{"type":"string"},"status":{"type":"string","enum":["pending","accepted"]},"expiresAt":{"type":"string","format":"date-time"}}},"StudyTemplateInvitationResult":{"type":"object","required":["invitations","emailFailures","message"],"properties":{"invitations":{"type":"array","items":{"$ref":"#/components/schemas/StudyTemplateInvitation"}},"emailFailures":{"type":"array","items":{"type":"string","format":"email"},"description":"Invited, but the email was not delivered. Share the link another way."},"message":{"type":"string"}}},"StudyTemplateAsset":{"type":"object","additionalProperties":false,"required":["id","name","url"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"url":{"type":"string"},"path":{"type":"string"},"mimeType":{"type":"string"},"kind":{"type":"string","enum":["link"]},"sizeBytes":{"type":"number","minimum":0},"mediaType":{"type":"string","enum":["video"]}}},"StudyTemplateConfiguration":{"type":"object","additionalProperties":false,"required":["version","goal","studyLocale","questions","methodId"],"properties":{"version":{"type":"integer","enum":[1]},"goal":{"type":"string","enum":["concept","comparison","website","pricing","market","explore"]},"studyLocale":{"type":"string","enum":["ar","de","en","es","fr","ja","ko","tr","zh"]},"methodId":{"type":"string","description":"A registered research method that is currently available. Methods that design their own tasks at execution (Van Westendorp, MaxDiff, Kano, NPS, …) keep only the qualitative questions in `questions`."},"questions":{"type":"array","minItems":1,"items":{"type":"object","additionalProperties":false,"required":["text","response"],"properties":{"text":{"type":"string"},"response":{"$ref":"#/components/schemas/StudyTemplateQuestionResponse"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/StudyTemplateAsset"},"default":[]}}}}}},"StudyTemplate":{"type":"object","required":["id","name","revision","configuration","createdAt","updatedAt","isSharedWithTeam","canManage","canShareWithTeam"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"revision":{"type":"integer","minimum":1},"isSharedWithTeam":{"type":"boolean"},"canManage":{"type":"boolean","description":"Only the owner may update, delete or share this template."},"canShareWithTeam":{"type":"boolean","description":"The owner has a team, or can turn off existing sharing."},"configuration":{"$ref":"#/components/schemas/StudyTemplateConfiguration"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"StudyTemplateCreateInput":{"type":"object","additionalProperties":false,"required":["name","configuration"],"properties":{"requestId":{"type":"string","format":"uuid","description":"Reuse only for retries of the same save."},"name":{"type":"string","minLength":1,"maxLength":200},"configuration":{"$ref":"#/components/schemas/StudyTemplateConfiguration"}}},"StudyTemplateUpdateInput":{"type":"object","additionalProperties":false,"required":["expectedRevision"],"anyOf":[{"required":["name"]},{"required":["configuration"]},{"required":["isSharedWithTeam"]}],"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"configuration":{"$ref":"#/components/schemas/StudyTemplateConfiguration"},"expectedRevision":{"type":"integer","minimum":1},"isSharedWithTeam":{"type":"boolean","description":"Owner only. Share with the authenticated owner’s current team, or turn sharing off."}}},"StudyTemplateUseInput":{"type":"object","additionalProperties":false,"required":["expectedRevision","requestId"],"properties":{"expectedRevision":{"type":"integer","minimum":1},"requestId":{"type":"string","format":"uuid","description":"Unique per intended draft; reuse only for retries."}}},"ResearchQuestionCondition":{"type":"object","additionalProperties":false,"required":["questionId"],"oneOf":[{"required":["answerIn"]},{"required":["answerNotIn"]},{"required":["categoryIn"]},{"required":["categoryNotIn"]}],"description":"Ask this question only of respondents whose own answer to an earlier question matched. Give exactly one of: answerIn (asked when the respondent chose any of these options) or answerNotIn (asked when it chose none of them) for an earlier categorical or multiselect question, using its option labels exactly; or categoryIn / categoryNotIn for an earlier open (qualitative) question, which codes each respondent's own answer into one of the categories named for that question (one coding frame per question, at most 12 categories) after it has been answered and before this question runs. An answer that fits none of the categories counts as none of them. Scale and ranking questions cannot gate. Respondents not asked are recorded as not asked and excluded from this question's results.","properties":{"questionId":{"type":"string","minLength":1,"maxLength":80,"description":"Id of the earlier question whose answer decides."},"answerIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"answerNotIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"categoryIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"categoryNotIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}}}},"ResearchQuestionResponse":{"oneOf":[{"type":"object","required":["type"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["qualitative"]}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["categorical"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answer choices shown to every Mind."}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["multiselect"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answers from which each Mind may select multiple choices."},"maxSelections":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum choices each respondent may select."}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["ranking"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answers every Mind puts in order, first to last. Results report first places as the distribution plus each option's mean rank."}}},{"type":"object","required":["type"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["scale"]},"unit":{"type":"object","properties":{"kind":{"type":"string","enum":["currency","percentage","duration","length","mass","volume","custom"]},"code":{"type":"string","minLength":1,"maxLength":80,"description":"ISO 4217 currency code (EUR, USD); % for percentage; singular Intl unit identifier (hour, meter, kilogram, liter) for measurements; or a label of up to 80 characters for custom. Selecting a unit does not convert numbers or impose a range."}},"required":["kind","code"],"additionalProperties":false,"description":"Unit of a numeric (scale) answer. Values stay plain numbers; result surfaces display them in this unit."},"scalePoints":{"type":"array","minItems":2,"maxItems":100,"description":"Exhaustive allowed numeric scale answers in authored order. Preserve literal labels and values; do not add intermediate points.","items":{"type":"object","additionalProperties":false,"required":["label","value"],"properties":{"label":{"type":"string","minLength":1},"value":{"type":"number"}}}},"scaleRange":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number"},"description":"Optional inclusive finite numeric response bounds as [minimum, maximum]. Omit when the numeric response has no authored bounds."}}}],"description":"Confirmed response contract for a planned question."},"ResearchStudyPlan":{"type":"object","additionalProperties":true,"description":"Versioned research plan. Every question exposes its proposed or confirmed response contract.","properties":{"version":{"type":"integer","enum":[1]},"executionPolicy":{"type":"object","additionalProperties":false,"required":["sourcePolicy"],"properties":{"sourcePolicy":{"type":"string","enum":["request_only","auto"],"description":"Checksum-locked evidence policy for the confirmed run. request_only is the controlled-Study default; auto is an explicit experimental opt-in."},"videoAnalysisStyle":{"type":"string","enum":["record","analyst"],"description":"Register of the one video summary every Mind of this run reads. record (default) writes down the spoken script, the visible scenes and the on-screen text; analyst deliberately reproduces the pre-2026-09 prompt, which reads tone and intent and raises the panel's positive rating bias."},"mindSourcePolicyOverrides":{"type":"array","maxItems":2000,"description":"Deterministically ordered, checksum-lockable per-Mind experiment assignments. Unlisted Minds use sourcePolicy.","items":{"type":"object","additionalProperties":false,"required":["mindId","sourcePolicy"],"properties":{"mindId":{"type":"string","format":"uuid"},"sourcePolicy":{"type":"string","enum":["request_only","auto"]}}}}}},"modules":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"questions":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"text":{"type":"string"},"response":{"oneOf":[{"type":"object","required":["type"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["qualitative"]}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["categorical"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answer choices shown to every Mind."}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["multiselect"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answers from which each Mind may select multiple choices."},"maxSelections":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum choices each respondent may select."}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["ranking"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answers every Mind puts in order, first to last. Results report first places as the distribution plus each option's mean rank."}}},{"type":"object","required":["type"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["scale"]},"unit":{"type":"object","properties":{"kind":{"type":"string","enum":["currency","percentage","duration","length","mass","volume","custom"]},"code":{"type":"string","minLength":1,"maxLength":80,"description":"ISO 4217 currency code (EUR, USD); % for percentage; singular Intl unit identifier (hour, meter, kilogram, liter) for measurements; or a label of up to 80 characters for custom. Selecting a unit does not convert numbers or impose a range."}},"required":["kind","code"],"additionalProperties":false,"description":"Unit of a numeric (scale) answer. Values stay plain numbers; result surfaces display them in this unit."},"scalePoints":{"type":"array","minItems":2,"maxItems":100,"description":"Exhaustive allowed numeric scale answers in authored order. Preserve literal labels and values; do not add intermediate points.","items":{"type":"object","additionalProperties":false,"required":["label","value"],"properties":{"label":{"type":"string","minLength":1},"value":{"type":"number"}}}},"scaleRange":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number"},"description":"Optional inclusive finite numeric response bounds as [minimum, maximum]. Omit when the numeric response has no authored bounds."}}}],"description":"Confirmed response contract for a planned question."},"askIf":{"type":"object","additionalProperties":false,"required":["questionId"],"oneOf":[{"required":["answerIn"]},{"required":["answerNotIn"]},{"required":["categoryIn"]},{"required":["categoryNotIn"]}],"description":"Ask this question only of respondents whose own answer to an earlier question matched. Give exactly one of: answerIn (asked when the respondent chose any of these options) or answerNotIn (asked when it chose none of them) for an earlier categorical or multiselect question, using its option labels exactly; or categoryIn / categoryNotIn for an earlier open (qualitative) question, which codes each respondent's own answer into one of the categories named for that question (one coding frame per question, at most 12 categories) after it has been answered and before this question runs. An answer that fits none of the categories counts as none of them. Scale and ranking questions cannot gate. Respondents not asked are recorded as not asked and excluded from this question's results.","properties":{"questionId":{"type":"string","minLength":1,"maxLength":80,"description":"Id of the earlier question whose answer decides."},"answerIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"answerNotIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"categoryIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"categoryNotIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}}}},"attachmentIds":{"type":"array","uniqueItems":true,"items":{"type":"string"},"description":"Durable Study-asset IDs assigned only to this question; [] means no assets. A question without attachmentIds receives every asset, and an asset no question lists is shown with every question instead of refusing the run."}}}}}}}}},"FixedInstrumentQuestions":{"type":"array","minItems":1,"maxItems":200,"description":"Fixed instrument. When present the planner is bypassed: every question is stored verbatim (whitespace collapsed), in this order, with exactly this response contract, except that a question sent as qualitative (or as a choice without options) whose own text lists its answers is stored as the choice question that text states: single choice, multiselect or ranking. Use `edits` on the saved revision to set it back to qualitative. Consecutive questions sharing a module label form one module. Cannot be combined with refinement, answers, questionResponses, or suggestQuestionStimuli. Repeated question texts or colliding ids are rejected.","items":{"type":"object","required":["text","response"],"additionalProperties":false,"properties":{"id":{"type":"string","maxLength":80,"description":"Stable item id; lower-cased to a slug. Defaults to q<position>."},"text":{"type":"string","maxLength":2000,"description":"Exact respondent-visible question text, including any anchors or labels. Skip and filter instructions (\"No -> go to Q12\", \"only if Q3 = Yes\") do not belong in the text either: transcribe each as askIf. A jump from an answer of item G to item N gives every item between G and N answerNotIn [that answer]; a filter gives answerIn. Tell the person about any instruction you cannot map to exact items and options instead of guessing it."},"module":{"type":"string","maxLength":200,"description":"Optional module (battery) label; consecutive questions with the same label are grouped."},"response":{"oneOf":[{"type":"object","required":["type"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["qualitative"]}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["categorical"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answer choices shown to every Mind."}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["multiselect"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answers from which each Mind may select multiple choices."},"maxSelections":{"type":"integer","minimum":1,"maximum":100,"description":"Maximum choices each respondent may select."}}},{"type":"object","required":["type","categoricalOptions"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["ranking"]},"categoricalOptions":{"type":"array","minItems":2,"maxItems":100,"uniqueItems":true,"items":{"type":"string","minLength":1},"description":"Predefined answers every Mind puts in order, first to last. Results report first places as the distribution plus each option's mean rank."}}},{"type":"object","required":["type"],"additionalProperties":false,"properties":{"type":{"type":"string","enum":["scale"]},"unit":{"type":"object","properties":{"kind":{"type":"string","enum":["currency","percentage","duration","length","mass","volume","custom"]},"code":{"type":"string","minLength":1,"maxLength":80,"description":"ISO 4217 currency code (EUR, USD); % for percentage; singular Intl unit identifier (hour, meter, kilogram, liter) for measurements; or a label of up to 80 characters for custom. Selecting a unit does not convert numbers or impose a range."}},"required":["kind","code"],"additionalProperties":false,"description":"Unit of a numeric (scale) answer. Values stay plain numbers; result surfaces display them in this unit."},"scalePoints":{"type":"array","minItems":2,"maxItems":100,"description":"Exhaustive allowed numeric scale answers in authored order. Preserve literal labels and values; do not add intermediate points.","items":{"type":"object","additionalProperties":false,"required":["label","value"],"properties":{"label":{"type":"string","minLength":1},"value":{"type":"number"}}}},"scaleRange":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number"},"description":"Optional inclusive finite numeric response bounds as [minimum, maximum]. Omit when the numeric response has no authored bounds."}}}],"description":"Confirmed response contract for a planned question."},"askIf":{"type":"object","additionalProperties":false,"required":["questionId"],"oneOf":[{"required":["answerIn"]},{"required":["answerNotIn"]},{"required":["categoryIn"]},{"required":["categoryNotIn"]}],"description":"Ask this question only of respondents whose own answer to an earlier question matched. Give exactly one of: answerIn (asked when the respondent chose any of these options) or answerNotIn (asked when it chose none of them) for an earlier categorical or multiselect question, using its option labels exactly; or categoryIn / categoryNotIn for an earlier open (qualitative) question, which codes each respondent's own answer into one of the categories named for that question (one coding frame per question, at most 12 categories) after it has been answered and before this question runs. An answer that fits none of the categories counts as none of them. Scale and ranking questions cannot gate. Respondents not asked are recorded as not asked and excluded from this question's results.","properties":{"questionId":{"type":"string","minLength":1,"maxLength":80,"description":"Id of the earlier question whose answer decides."},"answerIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"answerNotIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"categoryIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}},"categoryNotIn":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","minLength":1,"maxLength":500}}}}}}},"NumericUnit":{"type":"object","properties":{"kind":{"type":"string","enum":["currency","percentage","duration","length","mass","volume","custom"]},"code":{"type":"string","minLength":1,"maxLength":80,"description":"ISO 4217 currency code (EUR, USD); % for percentage; singular Intl unit identifier (hour, meter, kilogram, liter) for measurements; or a label of up to 80 characters for custom. Selecting a unit does not convert numbers or impose a range."}},"required":["kind","code"],"additionalProperties":false,"description":"Unit of a numeric (scale) answer. Values stay plain numbers; result surfaces display them in this unit."},"StudyTemplateQuestionResponse":{"type":"object","properties":{"type":{"type":"string","enum":["qualitative","categorical","multiselect","ranking","scale"]},"unit":{"type":"object","properties":{"kind":{"type":"string","enum":["currency","percentage","duration","length","mass","volume","custom"]},"code":{"type":"string","minLength":1,"maxLength":80,"description":"ISO 4217 currency code (EUR, USD); % for percentage; singular Intl unit identifier (hour, meter, kilogram, liter) for measurements; or a label of up to 80 characters for custom. Selecting a unit does not convert numbers or impose a range."}},"required":["kind","code"],"additionalProperties":false},"scaleRange":{"minItems":2,"maxItems":2,"type":"array","items":{"type":"number"}},"categoricalOptions":{"maxItems":100,"type":"array","items":{"type":"string","minLength":1,"maxLength":2000}},"maxSelections":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["type"],"additionalProperties":false}},"securitySchemes":{"ApiKeyAuth":{"type":"http","scheme":"bearer","bearerFormat":"API Key","description":"Personal API key. Format: `Bearer minds_…_key`. Create one at https://getminds.ai/settings/api-keys."}}},"security":[{"ApiKeyAuth":[]}]}