{"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/v1/groups/from-brief":{"post":{"parameters":[],"responses":{"201":{"description":"Grounded group created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/GroupFromBriefResult"}}}}}},"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`)."},"422":{"description":"No personas could be derived from the brief."},"500":{"description":"Internal server error."}},"operationId":"createGroupFromBrief","summary":"Create a grounded group from a brief","description":"Create one spark group from a free-text audience brief. The server gathers optional attachment/link/keyword context, researches real-world grounding data when available, generates personas, creates the sparks, and returns the new group plus optional grounding metadata.","tags":["Groups"],"security":[{"ApiKeyAuth":[]}],"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 group name override. When omitted, the server names the group from the brief or detected personas."},"files":{"type":"array","description":"Already-uploaded file attachments to include as context.","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"}},"isLinkSharingEnabled":{"type":"boolean","description":"Enable public link sharing for the created group."}}},"examples":{"demographicAudience":{"summary":"Create an audience group","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/panels/{panelId}/ask":{"post":{"parameters":[{"in":"path","name":"panelId","required":true,"description":"Panel UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"SSE stream of panel generation events.","content":{"text/event-stream":{"schema":{"type":"string","description":"Server-Sent Events stream. Each `data:` payload is a JSON object matching `PanelAskSseEvent`."},"examples":{"result":{"summary":"Final result event","value":"data: {\"type\":\"result\",\"outputData\":{\"title\":\"Rate this 1-5\",\"type\":\"scale\",\"groups\":[]},\"outputType\":\"bar\"}\\n\\n"}}}},"x-event-schema":{"$ref":"#/components/schemas/PanelAskSseEvent"}},"400":{"description":"Missing question, invalid panel ID, invalid model override, no attached groups, or no minds in selected groups."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the panel, or plan message limit reached (`code: PLAN_LIMIT`)."},"404":{"description":"Panel does not exist."},"500":{"description":"Internal server error."}},"operationId":"askPanel","summary":"Ask a panel question","description":"Send a question to all minds in a panel or a selected subset of attached groups. Returns a Server-Sent Events stream with start, optional classification, per-mind answers, aggregation progress, final output data, and done events.","tags":["Panels"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PanelAskRequest"},"examples":{"basic":{"summary":"Ask all groups","value":{"question":"On a scale of 1-10, how likely are you to recommend this product?"}},"withContext":{"summary":"Ask selected groups with context","value":{"question":"What should we improve in this onboarding flow?","groupIds":["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/panels/{panelId}/export-download":{"get":{"parameters":[{"in":"path","name":"panelId","required":true,"description":"Panel UUID.","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"jobId","required":false,"description":"Completed export job ID. Optional when the panel already has a persisted export.","schema":{"type":"string"}}],"responses":{"200":{"description":"PDF export file.","headers":{"Content-Disposition":{"description":"Attachment filename for the PDF.","schema":{"type":"string"}}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Job is not completed, or the target flow is not a panel."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the panel."},"404":{"description":"Panel, export job, or generated file does not exist."},"500":{"description":"Storage not configured, download failed, or internal server error."}},"operationId":"downloadPanelExport","summary":"Download a panel PDF export","description":"Download the latest persisted PDF export for a panel, or a completed PDF export job when `jobId` is provided.","tags":["Panels"],"security":[{"ApiKeyAuth":[]}]}},"/api/v1/panels/{panelId}/export-status":{"get":{"parameters":[{"in":"path","name":"panelId","required":true,"description":"Panel 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"}}],"responses":{"200":{"description":"Export status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PanelExportStatusResponse"}}}},"400":{"description":"Invalid panel ID or unsupported panel flow."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the panel."},"404":{"description":"Panel, export job, or completed export does not exist."},"500":{"description":"Internal server error."}},"operationId":"getPanelExportStatus","summary":"Get panel export status","description":"Check the status of a queued PDF export job. If `jobId` is omitted and the panel has a persisted export, returns that completed export immediately.","tags":["Panels"],"security":[{"ApiKeyAuth":[]}]}},"/api/v1/panels/{panelId}/export":{"post":{"parameters":[{"in":"path","name":"panelId","required":true,"description":"Panel UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Export created or queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PanelExportResponse"}}}},"400":{"description":"Invalid panel ID, unsupported panel flow, or invalid export format."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller cannot access the panel."},"404":{"description":"Panel does not exist."},"500":{"description":"Internal server error."}},"operationId":"exportPanel","summary":"Export panel results","description":"Export all answered panel questions. Markdown exports return the report content immediately. PDF exports enqueue an asynchronous job and return a job ID that can be polled with `getPanelExportStatus`.","tags":["Panels"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PanelExportRequest"},"examples":{"markdown":{"summary":"Synchronous Markdown export","value":{"format":"md"}},"pdf":{"summary":"Queued PDF export","value":{"format":"pdf"}}}}}}}},"/api/v1/panels":{"get":{"parameters":[{"in":"query","name":"limit","required":false,"description":"Max panels per page.","schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"in":"query","name":"offset","required":false,"description":"Number of panels to skip.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of panels.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Panel"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Missing or invalid API key."},"500":{"description":"Internal server error."}},"operationId":"listPanels","summary":"List panels","description":"List panel-mode flows (multi-spark panel chats) owned by the authenticated user. Each panel embeds its attached groups and their member sparks.","tags":["Panels"],"security":[{"ApiKeyAuth":[]}]},"post":{"parameters":[],"responses":{"201":{"description":"Panel created.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Panel"}}}}}},"400":{"description":"Missing `name`."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Plan limit reached (`code: PLAN_LIMIT`)."},"404":{"description":"One or more `groupIds` not found or not accessible to the caller."},"500":{"description":"Internal server error."}},"operationId":"createPanel","summary":"Create a panel","description":"Create a new panel-mode flow. Optionally attach one or more existing spark groups (the caller must have access to each — owner, member, team-shared, or public).","tags":["Panels"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Panel name."},"groupIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"IDs of spark groups to attach. De-duplicated server-side."},"isLinkSharingEnabled":{"type":"boolean","description":"Enable public link sharing for the panel and its attached groups/Minds."}}}}}}}},"/api/v1/sparks/{sparkId}":{"get":{"parameters":[{"in":"path","name":"sparkId","required":true,"description":"Spark UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Spark detail.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/SparkDetail"}}}}}},"400":{"description":"Invalid spark ID format (not a UUID)."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller does not have access to this spark."},"404":{"description":"Spark does not exist."},"500":{"description":"Internal server error."}},"operationId":"getSpark","summary":"Get a spark by ID","description":"Retrieve full details for a single spark, including its 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 spark is not public.","tags":["Sparks"],"security":[{"ApiKeyAuth":[]}]}},"/api/v1/sparks/{sparkId}/retrain":{"post":{"parameters":[{"in":"path","name":"sparkId","required":true,"description":"Spark UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Retrain queued.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingStatus"}}}},"400":{"description":"Invalid spark ID format (not a UUID)."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller does not own this spark."},"404":{"description":"Spark does not exist."},"409":{"description":"Mind is still queued or running — a retrain is already in flight."},"500":{"description":"Internal server error."}},"operationId":"retrainSpark","summary":"Retrain a mind","description":"Re-run training for a mind that has finished (status `completed` or `failed`). Atomically claims the mind back to `queued` and re-enqueues the auto-spark worker. Returns 409 if the mind is still `queued` or `running` (a retrain is already in flight). The response is the fresh training block — poll GET /v1/sparks/{id}/training until `readyToChat` is true.","tags":["Sparks"],"security":[{"ApiKeyAuth":[]}]}},"/api/v1/sparks/{sparkId}/training":{"get":{"parameters":[{"in":"path","name":"sparkId","required":true,"description":"Spark UUID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Training status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TrainingStatus"}}}},"400":{"description":"Invalid spark ID format (not a UUID)."},"401":{"description":"Missing or invalid API key."},"403":{"description":"Caller does not have access to this spark."},"404":{"description":"Spark does not exist."},"500":{"description":"Internal server error."}},"operationId":"getSparkTrainingStatus","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. `manual`-mode minds are `completed` immediately. Statuses are `queued`, `running`, `completed`, `failed` (there is no `idle`). On `failed`, `error.retryable` indicates whether `POST /v1/sparks/{id}/retrain` is worth calling.","tags":["Sparks"],"security":[{"ApiKeyAuth":[]}]}},"/api/v1/sparks":{"get":{"parameters":[{"in":"query","name":"search","description":"Case-insensitive substring match against name, description, and discipline.","required":false,"schema":{"type":"string"}},{"in":"query","name":"limit","description":"Max sparks per page.","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":100}},{"in":"query","name":"offset","description":"Number of sparks to skip.","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of sparks.","content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SparkSummary"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"400":{"description":"Invalid `limit` or `offset`."},"401":{"description":"Missing or invalid API key."},"500":{"description":"Internal server error."}},"operationId":"listSparks","summary":"List sparks (minds)","description":"List all sparks (AI minds) owned by the authenticated user. Supports text search by name/description/discipline and offset-based pagination. Ephemeral sparks (created during in-product chats) are excluded.","tags":["Sparks"],"security":[{"ApiKeyAuth":[]}]},"post":{"parameters":[],"responses":{"201":{"description":"Spark created. The `training` block carries the initial lifecycle state: `queued` for auto modes, `completed` for `manual`.","content":{"application/json":{"schema":{"type":"object","required":["data","training"],"properties":{"data":{"$ref":"#/components/schemas/SparkSummary"},"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`)."},"500":{"description":"Internal server error."}},"operationId":"createSpark","summary":"Create a spark (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/sparks/{id}/training` until `readyToChat` is true), while `manual` minds are `completed` immediately. A mind's `id` exists before it is ready — do not chat until `readyToChat` is true.","tags":["Sparks"],"security":[{"ApiKeyAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSparkRequest"},"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"}}}}}}}}},"components":{"schemas":{"GroupFromBriefResult":{"type":"object","required":["id","name","sparkCount","sparks","createdAt","updatedAt","isPublic","isSharedWithTeam","isLinkSharingEnabled","currentMemberRole","grounding"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"sparkCount":{"type":"integer"},"sparks":{"type":"array","items":{"$ref":"#/components/schemas/GroupSparkSummary"}},"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"]},"grounding":{"oneOf":[{"$ref":"#/components/schemas/GroupGrounding"},{"type":"null"}]}}},"GroupSparkSummary":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"discipline":{"type":["string","null"]},"profileImageUrl":{"type":["string","null"]}}},"GroupGrounding":{"type":"object","required":["distributions","sources","summary","confidence"],"properties":{"distributions":{"type":"array","items":{"$ref":"#/components/schemas/GroundingDistribution"}},"sources":{"type":"array","items":{"$ref":"#/components/schemas/GroundingSource"}},"summary":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1},"suggestedMinGroupSize":{"type":"integer","minimum":3,"maximum":50}}},"GroundingDistribution":{"type":"object","required":["name","distribution"],"properties":{"name":{"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}}}},"tier":{"type":"string","enum":["target","broader","general","global"]}}},"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"}}},"PanelAskRequest":{"type":"object","required":["question"],"properties":{"question":{"type":"string","minLength":1,"description":"Research question to ask the panel."},"groupIds":{"type":"array","description":"Optional subset of attached group UUIDs to ask. Defaults to all groups on the panel.","items":{"type":"string","format":"uuid"}},"attachments":{"type":"array","description":"Files or images to process once and include as context for every panelist.","items":{"$ref":"#/components/schemas/PanelAttachment"}},"links":{"type":"array","description":"Web links to fetch and summarize for context.","items":{"$ref":"#/components/schemas/PanelContextLink"}},"keywords":{"type":"array","description":"Keyword/source pairs to fetch and summarize for context.","items":{"$ref":"#/components/schemas/PanelKeywordContext"}},"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`."},"disableDiversityCheck":{"type":"boolean","default":false,"description":"Skip the diversity-enforced regeneration loop for benchmark or ablation runs."},"disableQuestionClassifier":{"type":"boolean","default":false,"description":"Skip automatic scale/categorical/qualitative classification."}}},"PanelAttachment":{"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."}}},"PanelContextLink":{"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"}}},"PanelKeywordContext":{"type":"object","properties":{"label":{"type":"string","description":"Keyword or topic label."},"url":{"type":"string","description":"Optional source URL for the keyword."},"id":{"type":"string"}}},"PanelAskSseEvent":{"oneOf":[{"$ref":"#/components/schemas/PanelAskStartEvent"},{"$ref":"#/components/schemas/PanelAskClassificationEvent"},{"$ref":"#/components/schemas/PanelAskAnswerEvent"},{"$ref":"#/components/schemas/PanelAskAggregatingEvent"},{"$ref":"#/components/schemas/PanelAskResultEvent"},{"$ref":"#/components/schemas/PanelAskDoneEvent"}]},"PanelAskStartEvent":{"type":"object","required":["type","total"],"properties":{"type":{"type":"string","enum":["start"]},"total":{"type":"integer","description":"Total number of minds that will answer."}}},"PanelAskClassificationEvent":{"type":"object","required":["type","classification"],"properties":{"type":{"type":"string","enum":["classification"]},"classification":{"$ref":"#/components/schemas/PanelQuestionClassification"}}},"PanelAskAnswerEvent":{"type":"object","required":["type","sparkId","sparkName","groupId","groupName","answer"],"properties":{"type":{"type":"string","enum":["answer"]},"sparkId":{"type":"string","format":"uuid"},"sparkName":{"type":"string"},"discipline":{"type":["string","null"]},"profileImageUrl":{"type":["string","null"]},"groupId":{"type":"string","format":"uuid"},"groupName":{"type":"string"},"answer":{"type":"string"}}},"PanelAskAggregatingEvent":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["aggregating"]}}},"PanelAskResultEvent":{"type":"object","required":["type","outputData","outputType"],"properties":{"type":{"type":"string","enum":["result"]},"outputData":{"$ref":"#/components/schemas/PanelOutputData"},"outputType":{"type":"string","enum":["bar"]}}},"PanelAskDoneEvent":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["done"]}}},"PanelQuestionClassification":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["scale","categorical","qualitative"]},"scaleRange":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"number"}},"options":{"type":"array","items":{"type":"string"}}}},"PanelOutputData":{"type":"object","required":["title","type","groups"],"properties":{"title":{"type":"string"},"type":{"type":"string","enum":["scale","categorical","qualitative"]},"classification":{"$ref":"#/components/schemas/PanelQuestionClassification"},"groups":{"type":"array","items":{"$ref":"#/components/schemas/PanelOutputGroup"}}}},"PanelOutputGroup":{"type":"object","required":["group","value","answers"],"properties":{"group":{"type":"string"},"value":{"type":"string"},"alignmentScore":{"type":"integer","minimum":0,"maximum":100},"answers":{"type":"array","items":{"$ref":"#/components/schemas/PanelOutputAnswer"}}}},"PanelOutputAnswer":{"type":"object","required":["value","persona","message"],"properties":{"value":{"type":"string"},"persona":{"type":"string"},"discipline":{"type":["string","null"]},"message":{"type":"string"},"imageUrl":{"type":["string","null"]},"reliabilityScore":{"type":"integer","minimum":0,"maximum":100}}},"PanelExportRequest":{"type":"object","properties":{"format":{"type":"string","enum":["md","pdf"],"default":"md","description":"`md` returns Markdown content immediately. `pdf` queues a branded PDF export job."}}},"PanelExportResponse":{"oneOf":[{"$ref":"#/components/schemas/PanelMarkdownExportResponse"},{"$ref":"#/components/schemas/PanelPdfExportJobResponse"}]},"PanelMarkdownExportResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["format","content"],"properties":{"format":{"type":"string","enum":["md"]},"content":{"type":"string","description":"Markdown report content."}}}}},"PanelPdfExportJobResponse":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["format","jobId","status"],"properties":{"format":{"type":"string","enum":["pdf"]},"jobId":{"type":"string","description":"BullMQ export job ID."},"status":{"type":"string","enum":["queued"]}}}}},"PanelExportStatusResponse":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/PanelExportStatus"}}},"PanelExportStatus":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["idle","queued","processing","completed","failed"]},"progress":{"type":"number","minimum":0,"maximum":100},"downloadUrl":{"type":"string","description":"Pre-signed or authenticated URL for the generated PDF."},"error":{"type":"string"},"generatedAt":{"type":["string","null"],"format":"date-time"}}},"Panel":{"type":"object","required":["id","name","flowMode","createdAt","updatedAt","messageCount","groups"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"flowMode":{"type":"string","enum":["panel"],"description":"Always `panel` on this endpoint."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"messageCount":{"type":"integer"},"isLinkSharingEnabled":{"type":"boolean"},"publicShareId":{"type":["string","null"],"format":"uuid"},"groups":{"type":"array","items":{"type":"object","required":["id","name","sparkCount","sparks"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"sparkCount":{"type":"integer"},"sparks":{"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"}}}}}}}}},"SparkDetail":{"type":"object","required":["id","name","description","type","tags","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 defining the spark's persona."},"tags":{"type":"array","items":{"type":"string"}},"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"],"description":"Current training lifecycle state. Poll GET /v1/sparks/{id}/training for full detail."},"readyToChat":{"type":"boolean","description":"True only when training has completed; a mind's id exists before it is ready."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"TrainingStatus":{"type":"object","required":["status","readyToChat"],"properties":{"status":{"type":"string","enum":["queued","running","completed","failed"],"description":"Training lifecycle state."},"readyToChat":{"type":"boolean","description":"True only when training has completed and the mind can answer."},"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)."},"error":{"type":["object","null"],"description":"Present only when status is `failed`.","required":["code","retryable"],"properties":{"code":{"type":"string","enum":["COLLECTION_FAILED","PROFILE_GEN_FAILED","TIMEOUT","INTERNAL"]},"retryable":{"type":"boolean","description":"When true, POST /v1/sparks/{id}/retrain may recover the mind."}}}}},"SparkSummary":{"type":"object","required":["id","name","description","type","tags","createdAt","updatedAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Spark ID."},"name":{"type":"string","description":"Spark display name."},"description":{"type":"string","description":"Short summary of the spark."},"type":{"type":"string","enum":["creative","expert","user"],"description":"Spark archetype."},"discipline":{"type":["string","null"],"description":"Area of expertise / domain."},"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"}}},"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."}}},"CreateSparkRequest":{"type":"object","required":["name","discipline"],"properties":{"name":{"type":"string","minLength":2,"maxLength":100,"description":"Spark 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":"External avatar URL; downloaded and persisted to Supabase storage."},"generateImage":{"type":"boolean","description":"Trigger async AI profile-image generation after creation. Defaults to true for auto-training modes; pass false to opt out."},"cloneVoice":{"type":"boolean","description":"Trigger async voice cloning via YouTube + Fish Audio (experimental)."},"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`."}}}},"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":[]}]}