{"openapi":"3.1.0","info":{"title":"Pascal Editor Scene API","version":"1.0.0","description":"Hosted REST + SSE API for agent access to Pascal Editor projects and 3D scene graphs. Native MCP is available at /api/mcp. Errors are JSON with a machine-readable `error` code; responses carry `RateLimit` headers; deprecated operations answer with `Deprecation` and a `rel=\"deprecation\"` link to the versioning policy.","contact":{"name":"Pascal support","email":"support@pascal.app","url":"https://editor.pascal.app/contact"},"termsOfService":"https://editor.pascal.app/terms","x-deprecation-policy":"https://editor.pascal.app/docs/developers/errors#versioning-and-deprecation"},"servers":[{"url":"https://editor.pascal.app"}],"externalDocs":{"description":"Connect an AI agent to Pascal with MCP or the Scene API","url":"https://editor.pascal.app/docs/developers/mcp"},"security":[{"bearerApiKey":[]}],"paths":{"/api/projects/{id}/files":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"get":{"operationId":"listProjectFiles","summary":"List uploads and completed project deliverables","description":"Requires project membership even for public scenes. Includes uploads, plugin files, snapshots, completed Studio outputs and workspace files explicitly linked to this project. Unlinked workspace files are excluded. Follow nextCursor until null. OAuth requires scene:read; workspace-scoped API keys retain their workspace boundary. Content URLs can be application-relative; resolve against this API origin and retain the caller authorization.","parameters":[{"in":"query","name":"collection","description":"Files excludes internal working artifacts. Project memory contains retained working artifacts; all includes both.","schema":{"enum":["files","project-memory","all"],"default":"files"}},{"in":"query","name":"query","schema":{"type":"string","maxLength":300}},{"in":"query","name":"type","schema":{"enum":["scan","guide","image","document","other"]}},{"in":"query","name":"cursor","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Newest files first","content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"object","required":["id","projectId","name","originalName","type","origin","url","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"projectId":{"type":"string"},"name":{"type":"string"},"originalName":{"type":"string"},"url":{"type":"string","format":"uri-reference"},"type":{"enum":["scan","guide","image","document","other"]},"origin":{"enum":["upload","plugin","snapshot","render","workspace"]},"typeLabel":{"type":["string","null"]},"mimeType":{"type":["string","null"]},"fileSize":{"type":["integer","null"]},"thumbnailUrl":{"type":["string","null"]},"notes":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"projectMemory":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["checkpoint","source","preview","review","comparison","conversion-map","scene-part"]},"runId":{"type":"string","minLength":1,"maxLength":200}},"required":["kind"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"nextCursor":{"type":["string","null"]}},"required":["files","nextCursor"]}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"}}}},"/api/projects/{id}/files/workspace":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"get":{"operationId":"listRelatedWorkspaceFiles","summary":"Browse files from other projects in this workspace","description":"The authorized anchor project determines the workspace. Excludes files already in the anchor project. Personal projects only include other projects owned by the same user. Search also matches project names. Workspace-scoped keys and OAuth scene:read are supported; project-bound executor and chat sandbox credentials cannot use this endpoint.","parameters":[{"in":"query","name":"collection","description":"Files excludes internal working artifacts. Project memory contains retained working artifacts; all includes both.","schema":{"enum":["files","project-memory","all"],"default":"files"}},{"in":"query","name":"query","schema":{"type":"string","maxLength":300}},{"in":"query","name":"type","schema":{"enum":["scan","guide","image","document","other"]}},{"in":"query","name":"cursor","schema":{"type":"string"}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Newest workspace files first, with their owning project names","content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"array","items":{"type":"object","required":["id","projectId","name","originalName","type","origin","url","createdAt","updatedAt","projectName"],"properties":{"id":{"type":"string"},"projectId":{"type":"string"},"name":{"type":"string"},"originalName":{"type":"string"},"url":{"type":"string","format":"uri-reference"},"type":{"enum":["scan","guide","image","document","other"]},"origin":{"enum":["upload","plugin","snapshot","render","workspace"]},"typeLabel":{"type":["string","null"]},"mimeType":{"type":["string","null"]},"fileSize":{"type":["integer","null"]},"thumbnailUrl":{"type":["string","null"]},"notes":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"projectMemory":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["checkpoint","source","preview","review","comparison","conversion-map","scene-part"]},"runId":{"type":"string","minLength":1,"maxLength":200}},"required":["kind"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"projectName":{"type":"string"}}}},"nextCursor":{"type":["string","null"]}},"required":["files","nextCursor"]}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"}}}},"/api/projects/{id}/files/uploads":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"post":{"operationId":"prepareProjectFileUpload","summary":"Prepare a direct file upload","description":"Requires project membership and OAuth scene:write when using OAuth. Returns a short-lived signedUrl; PUT raw bytes there with the supplied Content-Type, then complete at this endpoint with PUT. The file is listed only after completion. Maximum 500 MiB; SVG is refused. Names contain no path separators or control characters.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":400},"mimeType":{"type":"string","minLength":1,"maxLength":200},"size":{"type":"integer","minimum":0,"maximum":524288000},"type":{"type":"string","enum":["scan","guide","image","document","other"]},"source":{"default":"api","type":"string","enum":["editor","ai_chat","api","import"]},"projectMemory":{"type":"object","properties":{"kind":{"type":"string","enum":["checkpoint","source","preview","review","comparison","conversion-map","scene-part"]},"runId":{"type":"string","minLength":1,"maxLength":200}},"required":["kind"],"additionalProperties":false},"folderId":{"anyOf":[{"type":"string","pattern":"^folder_[A-Za-z0-9_-]+$"},{"type":"null"}]}},"required":["name","mimeType","size"],"additionalProperties":false}}}},"responses":{"201":{"description":"Upload destination; retain id and storageKey for completion retries","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"storageKey":{"type":"string"},"signedUrl":{"type":"string","format":"uri"}},"required":["id","storageKey","signedUrl"]}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"},"415":{"description":"Unsupported file type"}}},"put":{"operationId":"completeProjectFileUpload","summary":"Verify and register uploaded bytes","description":"Supply the original name, MIME type, size, and returned id and storageKey. Verifies stored size and project ownership. Retrying the same id is safe and does not create another catalog entry.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":400},"mimeType":{"type":"string","minLength":1,"maxLength":200},"size":{"type":"integer","minimum":0,"maximum":524288000},"type":{"type":"string","enum":["scan","guide","image","document","other"]},"source":{"default":"api","type":"string","enum":["editor","ai_chat","api","import"]},"projectMemory":{"type":"object","properties":{"kind":{"type":"string","enum":["checkpoint","source","preview","review","comparison","conversion-map","scene-part"]},"runId":{"type":"string","minLength":1,"maxLength":200}},"required":["kind"],"additionalProperties":false},"folderId":{"anyOf":[{"type":"string","pattern":"^folder_[A-Za-z0-9_-]+$"},{"type":"null"}]},"id":{"type":"string","pattern":"^asset_[A-Za-z0-9_-]+$"},"storageKey":{"type":"string","minLength":1,"maxLength":700}},"required":["name","mimeType","size","id","storageKey"],"additionalProperties":false}}}},"responses":{"200":{"description":"Project file metadata and download URL","content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"object","required":["id","projectId","name","originalName","type","origin","url","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"projectId":{"type":"string"},"name":{"type":"string"},"originalName":{"type":"string"},"url":{"type":"string","format":"uri-reference"},"type":{"enum":["scan","guide","image","document","other"]},"origin":{"enum":["upload","plugin","snapshot","render","workspace"]},"typeLabel":{"type":["string","null"]},"mimeType":{"type":["string","null"]},"fileSize":{"type":["integer","null"]},"thumbnailUrl":{"type":["string","null"]},"notes":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"projectMemory":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["checkpoint","source","preview","review","comparison","conversion-map","scene-part"]},"runId":{"type":"string","minLength":1,"maxLength":200}},"required":["kind"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"required":["file"]}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"},"409":{"description":"Bytes are not stored yet or file ID is already in use"},"415":{"description":"Unsupported file type"}}}},"/api/projects/{id}/files/{fileId}":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"fileId","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getProjectFile","summary":"Get project file metadata","responses":{"200":{"description":"Project file metadata and download URL","content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"object","required":["id","projectId","name","originalName","type","origin","url","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"projectId":{"type":"string"},"name":{"type":"string"},"originalName":{"type":"string"},"url":{"type":"string","format":"uri-reference"},"type":{"enum":["scan","guide","image","document","other"]},"origin":{"enum":["upload","plugin","snapshot","render","workspace"]},"typeLabel":{"type":["string","null"]},"mimeType":{"type":["string","null"]},"fileSize":{"type":["integer","null"]},"thumbnailUrl":{"type":["string","null"]},"notes":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"projectMemory":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["checkpoint","source","preview","review","comparison","conversion-map","scene-part"]},"runId":{"type":"string","minLength":1,"maxLength":200}},"required":["kind"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"required":["file"]}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"}}},"patch":{"operationId":"renameProjectFile","summary":"Rename a project file","description":"Requires project membership and OAuth scene:write when using OAuth. Preserves identity and content location; updates the owning Studio record when applicable. Renaming a linked workspace file changes its canonical name in every linked project.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":400}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Project file metadata and download URL","content":{"application/json":{"schema":{"type":"object","properties":{"file":{"type":"object","required":["id","projectId","name","originalName","type","origin","url","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"projectId":{"type":"string"},"name":{"type":"string"},"originalName":{"type":"string"},"url":{"type":"string","format":"uri-reference"},"type":{"enum":["scan","guide","image","document","other"]},"origin":{"enum":["upload","plugin","snapshot","render","workspace"]},"typeLabel":{"type":["string","null"]},"mimeType":{"type":["string","null"]},"fileSize":{"type":["integer","null"]},"thumbnailUrl":{"type":["string","null"]},"notes":{"type":["string","null"]},"tags":{"type":"array","items":{"type":"string"}},"projectMemory":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["checkpoint","source","preview","review","comparison","conversion-map","scene-part"]},"runId":{"type":"string","minLength":1,"maxLength":200}},"required":["kind"],"additionalProperties":false},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"required":["file"]}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"}}},"delete":{"operationId":"deleteProjectFile","summary":"Remove a file from the project catalog","description":"Requires project membership and OAuth scene:write when using OAuth. Idempotent. For a linked workspace file, removes only this project association; the original and other links remain. Also removes a project-owned Studio file from Studio. Referenced storage bytes are retained; this operation does not guarantee erasure.","responses":{"200":{"description":"Catalog entry removed","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"const":true}},"required":["deleted"]}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"}}}},"/api/projects/{id}/files/{fileId}/content":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"fileId","required":true,"schema":{"type":"string"}}],"get":{"operationId":"downloadProjectFile","summary":"Resolve the current content URL","description":"Checks project membership and redirects to storage. Existing asset and Studio buckets remain public; this route is not a private-storage boundary.","responses":{"303":{"description":"Follow the Location header to the content","headers":{"Location":{"schema":{"type":"string","format":"uri"}}}},"400":{"description":"Invalid file request"},"401":{"description":"Authentication required"},"403":{"description":"Missing scene:read or scene:write OAuth scope"},"404":{"description":"Project or file not accessible to this workspace member"}}}},"/api/workspace/automations":{"get":{"operationId":"listProjectAutomations","summary":"List owned automations and recent project runs","description":"Requires a human browser session or a full-authority human-script API key. Current workspace membership and project edit access are checked. Agent and OAuth app credentials cannot manage persistent delegations.","parameters":[{"name":"workspaceId","in":"query","required":true,"schema":{"type":"string"},"description":"personal:<user-id> or organization:<organization-id>; must match the authenticated workspace."}],"responses":{"200":{"description":"Automations, recent runs, projects and available models","content":{"application/json":{"schema":{"type":"object","properties":{"automations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"revision":{"type":"number"},"specification":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"maxLength":100},"instructions":{"type":"string","minLength":1,"maxLength":16000},"engine":{"default":{"type":"architect","effort":"medium"},"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"architect"},"effort":{"type":"string","enum":["low","medium","high","pro"]}},"required":["type","effort"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"model"},"modelId":{"type":"string","minLength":1,"maxLength":160},"effort":{"type":"string","enum":["none","minimal","low","medium","high","xhigh"]}},"required":["type","modelId"],"additionalProperties":false}]},"connectionIds":{"default":[],"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"maxCredits":{"type":"number","minimum":1,"maximum":10000},"maxDurationSeconds":{"default":900,"type":"integer","minimum":60,"maximum":3600},"callbackUrl":{"default":null,"anyOf":[{"type":"string","maxLength":2048,"format":"uri"},{"type":"null"}]},"name":{"type":"string","minLength":1,"maxLength":120},"enabled":{"default":true,"type":"boolean"},"eventType":{"default":null,"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"maxRunsPerHour":{"default":10,"type":"integer","minimum":1,"maximum":60},"maxDailyCredits":{"type":"number","minimum":1,"maximum":50000}},"required":["projectId","instructions","maxCredits","name","maxDailyCredits"],"additionalProperties":false},"createdAt":{"type":"string"},"webhookPath":{"type":"string"}},"required":["id","revision","specification","createdAt","webhookPath"]}},"runs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"automationId":{"type":["string","null"]},"automationRevision":{"type":["number","null"]},"projectId":{"type":"string"},"eventId":{"type":"string"},"eventType":{"type":"string"},"status":{"type":"string","enum":["queued","running","waiting","completed","failed","cancelled"]},"credits":{"type":"number","minimum":0},"invocationId":{"type":"string"},"threadId":{"type":"string"},"responseId":{"type":"string"},"interactionId":{"type":["string","null"]},"createdAt":{"type":"string"},"deadlineAt":{"type":"string"},"error":{"type":["string","null"]},"result":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}},{"type":"null"}]},"delivery":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"number"}},"required":["id","status","attempts"]},{"type":"null"}]}},"required":["id","automationId","automationRevision","projectId","eventId","eventType","status","credits","invocationId","threadId","responseId","interactionId","createdAt","deadlineAt","error","result","delivery"],"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]}}}}}}}}},"400":{"description":"Invalid settings or event","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Current owner and project edit permission required","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"Stale revision, workspace or idempotency conflict","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Queue, hourly run or reserved daily credit limit reached","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"manageProjectAutomations","summary":"Create, update, trigger and control project automations","description":"All UI, REST and hosted MCP entry points share admission. A trigger/run requires a stable eventId; retries return the same run. Updating requires the current revision. maxCredits uses the existing agent runtime: non-Pro model rounds and sandbox settlement can exceed this threshold. Daily admission reserves the configured maximum for every accepted run for 24 hours. A model is never silently substituted. Secrets appear only in authenticated create/reveal responses, never hosted MCP results.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string"},"command":{"oneOf":[{"type":"object","properties":{"action":{"type":"string","const":"create"},"specification":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"maxLength":100},"instructions":{"type":"string","minLength":1,"maxLength":16000},"engine":{"default":{"type":"architect","effort":"medium"},"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"architect"},"effort":{"type":"string","enum":["low","medium","high","pro"]}},"required":["type","effort"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"model"},"modelId":{"type":"string","minLength":1,"maxLength":160},"effort":{"type":"string","enum":["none","minimal","low","medium","high","xhigh"]}},"required":["type","modelId"],"additionalProperties":false}]},"connectionIds":{"default":[],"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"maxCredits":{"type":"number","minimum":1,"maximum":10000},"maxDurationSeconds":{"default":900,"type":"integer","minimum":60,"maximum":3600},"callbackUrl":{"default":null,"anyOf":[{"type":"string","maxLength":2048,"format":"uri"},{"type":"null"}]},"name":{"type":"string","minLength":1,"maxLength":120},"enabled":{"default":true,"type":"boolean"},"eventType":{"default":null,"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"maxRunsPerHour":{"default":10,"type":"integer","minimum":1,"maximum":60},"maxDailyCredits":{"type":"number","minimum":1,"maximum":50000}},"required":["projectId","instructions","maxCredits","name","maxDailyCredits"],"additionalProperties":false}},"required":["action","specification"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"update"},"id":{"type":"string","minLength":1,"maxLength":100},"revision":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"specification":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"maxLength":100},"instructions":{"type":"string","minLength":1,"maxLength":16000},"engine":{"default":{"type":"architect","effort":"medium"},"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"architect"},"effort":{"type":"string","enum":["low","medium","high","pro"]}},"required":["type","effort"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"model"},"modelId":{"type":"string","minLength":1,"maxLength":160},"effort":{"type":"string","enum":["none","minimal","low","medium","high","xhigh"]}},"required":["type","modelId"],"additionalProperties":false}]},"connectionIds":{"default":[],"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"maxCredits":{"type":"number","minimum":1,"maximum":10000},"maxDurationSeconds":{"default":900,"type":"integer","minimum":60,"maximum":3600},"callbackUrl":{"default":null,"anyOf":[{"type":"string","maxLength":2048,"format":"uri"},{"type":"null"}]},"name":{"type":"string","minLength":1,"maxLength":120},"enabled":{"default":true,"type":"boolean"},"eventType":{"default":null,"anyOf":[{"type":"string","minLength":1,"maxLength":120},{"type":"null"}]},"maxRunsPerHour":{"default":10,"type":"integer","minimum":1,"maximum":60},"maxDailyCredits":{"type":"number","minimum":1,"maximum":50000}},"required":["projectId","instructions","maxCredits","name","maxDailyCredits"],"additionalProperties":false}},"required":["action","id","revision","specification"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"reveal"},"id":{"type":"string","minLength":1,"maxLength":100},"rotate":{"default":false,"type":"boolean"}},"required":["action","id"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"trigger"},"id":{"type":"string","minLength":1,"maxLength":100},"event":{"type":"object","properties":{"type":{"type":"string","minLength":1,"maxLength":120},"time":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"data":{"$ref":"#/$defs/__schema0"}},"required":["type","data"],"additionalProperties":false},"eventId":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,100}$"}},"required":["action","id","event","eventId"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"run"},"specification":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"maxLength":100},"instructions":{"type":"string","minLength":1,"maxLength":16000},"engine":{"default":{"type":"architect","effort":"medium"},"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"architect"},"effort":{"type":"string","enum":["low","medium","high","pro"]}},"required":["type","effort"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"model"},"modelId":{"type":"string","minLength":1,"maxLength":160},"effort":{"type":"string","enum":["none","minimal","low","medium","high","xhigh"]}},"required":["type","modelId"],"additionalProperties":false}]},"connectionIds":{"default":[],"maxItems":20,"type":"array","items":{"type":"string","minLength":1,"maxLength":100}},"maxCredits":{"type":"number","minimum":1,"maximum":10000},"maxDurationSeconds":{"default":900,"type":"integer","minimum":60,"maximum":3600},"callbackUrl":{"default":null,"anyOf":[{"type":"string","maxLength":2048,"format":"uri"},{"type":"null"}]}},"required":["projectId","instructions","maxCredits"],"additionalProperties":false},"event":{"type":"object","properties":{"type":{"type":"string","minLength":1,"maxLength":120},"time":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"data":{"$ref":"#/$defs/__schema0"}},"required":["type","data"],"additionalProperties":false},"eventId":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,100}$"}},"required":["action","specification","event","eventId"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"inspect"},"id":{"type":"string","minLength":1,"maxLength":100}},"required":["action","id"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"cancel"},"id":{"type":"string","minLength":1,"maxLength":100}},"required":["action","id"],"additionalProperties":false},{"type":"object","properties":{"action":{"type":"string","const":"answer"},"id":{"type":"string","minLength":1,"maxLength":100},"interactionId":{"type":"string","minLength":1,"maxLength":100},"idempotencyKey":{"type":"string","pattern":"^[A-Za-z0-9_.:-]{1,100}$"},"answer":{"type":"string","minLength":1,"maxLength":8000}},"required":["action","id","interactionId","idempotencyKey","answer"],"additionalProperties":false}]}},"required":["workspaceId","command"],"additionalProperties":false,"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]}}}}}},"responses":{"200":{"description":"Updated automation or run","content":{"application/json":{"schema":{"type":"object"}}}},"201":{"description":"Automation and signing secrets created","content":{"application/json":{"schema":{"type":"object"}}}},"202":{"description":"Run accepted, possibly already admitted by a prior delivery","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid settings or event","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Current owner and project edit permission required","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"Stale revision, workspace or idempotency conflict","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Queue, hourly run or reserved daily credit limit reached","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/project-runs/{id}":{"get":{"operationId":"getProjectRun","summary":"Read an owned project run and callback delivery status","description":"Requires the owner’s current workspace credential and project edit access. The webhook signing secret does not grant output access. responseId addresses the canonical /v1/responses result.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Canonical run status","content":{"application/json":{"schema":{"type":"object","properties":{"run":{"type":"object","properties":{"id":{"type":"string"},"automationId":{"type":["string","null"]},"automationRevision":{"type":["number","null"]},"projectId":{"type":"string"},"eventId":{"type":"string"},"eventType":{"type":"string"},"status":{"type":"string","enum":["queued","running","waiting","completed","failed","cancelled"]},"credits":{"type":"number","minimum":0},"invocationId":{"type":"string"},"threadId":{"type":"string"},"responseId":{"type":"string"},"interactionId":{"type":["string","null"]},"createdAt":{"type":"string"},"deadlineAt":{"type":"string"},"error":{"type":["string","null"]},"result":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}},{"type":"null"}]},"delivery":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["pending","delivered","failed"]},"attempts":{"type":"number"}},"required":["id","status","attempts"]},{"type":"null"}]}},"required":["id","automationId","automationRevision","projectId","eventId","eventType","status","credits","invocationId","threadId","responseId","interactionId","createdAt","deadlineAt","error","result","delivery"]}},"required":["run"],"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]}}}}}},"400":{"description":"Invalid settings or event","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Current owner and project edit permission required","content":{"application/json":{"schema":{"type":"object"}}}},"404":{"description":"Run not found or no longer accessible","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"Stale revision, workspace or idempotency conflict","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Queue, hourly run or reserved daily credit limit reached","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/webhooks/project-automations/{automationId}":{"post":{"operationId":"deliverProjectAutomationEvent","summary":"Deliver a signed event to a saved automation","security":[],"description":"HMAC-SHA256 over timestamp + \".\" + event ID + \".\" + exact request body, encoded as v1=<hex>. Signatures expire after five minutes. Reuse the same event ID and payload on retries with a fresh signature. The saved automation fixes the project, instructions, model, connections and limits; event data cannot choose them. Acceptance persists the run before asynchronous dispatch.","parameters":[{"name":"automationId","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Pascal-Event-Id","in":"header","required":true,"schema":{"type":"string","maxLength":100,"pattern":"^[A-Za-z0-9_.:-]+$"}},{"name":"X-Pascal-Timestamp","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9]{10}$"}},{"name":"X-Pascal-Signature","in":"header","required":true,"schema":{"type":"string","pattern":"^v1=[a-f0-9]{64}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","minLength":1,"maxLength":120},"time":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"data":{"$ref":"#/$defs/__schema0"}},"required":["type","data"],"additionalProperties":false,"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]}}}}}},"responses":{"202":{"description":"Durably accepted run ID, duplicate flag and authenticated status URL","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid settings or event","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Current owner and project edit permission required","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"Stale revision, workspace or idempotency conflict","content":{"application/json":{"schema":{"type":"object"}}}},"413":{"description":"Event exceeds 32 KB","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Queue, hourly run or reserved daily credit limit reached","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/workspace/connectors":{"get":{"operationId":"listWorkspaceConnections","summary":"Discover permitted workspace connections","parameters":[{"name":"workspaceId","in":"query","required":true,"schema":{"type":"string"},"description":"personal:<user-id> or organization:<organization-id>; must match the authenticated workspace."}],"responses":{"200":{"description":"Permission-filtered connections and provider capabilities","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Invalid settings or event","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Current owner and project edit permission required","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"Stale revision, workspace or idempotency conflict","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Queue, hourly run or reserved daily credit limit reached","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"manageCustomMcpConnections","summary":"Connect and approve a custom remote MCP server","description":"These commands extend the workspace connector API. Supports public HTTPS Streamable HTTP endpoints on port 443, with no authentication or a bearer token. URLs cannot include user information, query strings, fragments or redirects. No local STDIO or arbitrary OAuth server setup. Discovery executes no tools; exact tool schemas require owner approval and separate agent permission. Custom tool calls use capabilityId invoke plus an idempotencyKey through the existing execute command, or call_connector_tool over hosted MCP. A connection must be shared with the workspace for organization project agents.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string"},"command":{"oneOf":[{"type":"object","properties":{"action":{"type":"string","const":"connectMcp"},"configuration":{"type":"object","properties":{"endpoint":{"type":"string","maxLength":2048,"format":"uri"},"name":{"type":"string","minLength":1,"maxLength":200},"authentication":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"none"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"token"},"token":{"type":"string","minLength":1,"maxLength":4096,"pattern":"^[^\\r\\n]+$"}},"required":["type","token"],"additionalProperties":false}]},"connectionId":{"type":"string","maxLength":100},"generation":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["endpoint","authentication"],"additionalProperties":false}},"required":["action","configuration"]},{"type":"object","properties":{"action":{"type":"string","const":"mcpDetails"},"connectionId":{"type":"string","minLength":1,"maxLength":100}},"required":["action","connectionId"]},{"type":"object","properties":{"action":{"type":"string","const":"refreshMcp"},"connectionId":{"type":"string","minLength":1,"maxLength":100},"generation":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["action","connectionId","generation"]},{"type":"object","properties":{"action":{"type":"string","const":"approveMcp"},"configuration":{"type":"object","properties":{"connectionId":{"type":"string","minLength":1,"maxLength":100},"generation":{"type":"integer","minimum":0,"maximum":9007199254740991},"tools":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"schemaHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"allowAgents":{"type":"boolean"}},"required":["name","schemaHash","allowAgents"],"additionalProperties":false}}},"required":["connectionId","generation","tools"],"additionalProperties":false}},"required":["action","configuration"]}]}},"required":["workspaceId","command"],"additionalProperties":false}}}},"responses":{"200":{"description":"Reviewed MCP details","content":{"application/json":{"schema":{"type":"object","properties":{"details":{"type":"object","properties":{"connectionId":{"type":"string"},"generation":{"type":"integer","minimum":0,"maximum":9007199254740991},"endpoint":{"type":"string","format":"uri"},"authentication":{"type":"string","enum":["none","token","oauth"]},"server":{"type":"object","properties":{"name":{"type":"string"},"version":{"type":"string"}},"required":["name","version"]},"tools":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"title":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":16384},"inputSchema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}},"outputSchema":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema1"}},"annotations":{"type":"object","properties":{"readOnlyHint":{"type":"boolean"},"destructiveHint":{"type":"boolean"},"idempotentHint":{"type":"boolean"},"openWorldHint":{"type":"boolean"}}},"schemaHash":{"type":"string","pattern":"^[a-f0-9]{64}$"}},"required":["name","inputSchema","schemaHash"]}},"approvals":{"maxItems":100,"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"schemaHash":{"type":"string","pattern":"^[a-f0-9]{64}$"},"allowAgents":{"type":"boolean"}},"required":["name","schemaHash","allowAgents"],"additionalProperties":false}},"checkedAt":{"type":"string"}},"required":["connectionId","generation","endpoint","authentication","server","tools","approvals","checkedAt"]}},"required":["details"],"$defs":{"__schema0":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema0"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema0"}}]},"__schema1":{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"},{"type":"null"},{"type":"array","items":{"$ref":"#/$defs/__schema1"}},{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"$ref":"#/$defs/__schema1"}}]}}}}}},"201":{"description":"Connected MCP account","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string"},"workspaceId":{"type":"string"},"providerId":{"type":"string"},"name":{"type":"string","minLength":1,"maxLength":320},"mode":{"type":"string","enum":["sample","public","oauth","api_key","composio","mcp"]},"status":{"type":"string","enum":["connected","disconnected","error"]},"visibility":{"type":"string","enum":["private","workspace"]},"canAccess":{"type":"boolean"},"canManage":{"type":"boolean"},"canDisconnect":{"type":"boolean"},"connectedBy":{"type":"object","properties":{"id":{"type":["string","null"]},"name":{"type":"string"},"image":{"type":["string","null"]}},"required":["id","name","image"]},"generation":{"type":"integer","minimum":0,"maximum":9007199254740991},"resourceIds":{"type":"array","items":{"type":"string"}},"humanCapabilities":{"type":"array","items":{"type":"string"}},"agentCapabilities":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string"},"lastCheck":{"type":"object","properties":{"status":{"type":"string","enum":["running","passed","failed"]},"checkedAt":{"type":"string"},"message":{"type":"string"},"code":{"type":"string"}},"required":["status","checkedAt","message"]}},"required":["id","workspaceId","providerId","name","mode","status","visibility","canAccess","canManage","canDisconnect","connectedBy","generation","resourceIds","humanCapabilities","agentCapabilities","createdAt"]}},"required":["connection"]}}}},"400":{"description":"Invalid settings or event","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"type":"object"}}}},"403":{"description":"Current owner and project edit permission required","content":{"application/json":{"schema":{"type":"object"}}}},"409":{"description":"Stale revision, workspace or idempotency conflict","content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Queue, hourly run or reserved daily credit limit reached","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/api/auth/agent/register":{"get":{"operationId":"getAgentRegistrationInfo","summary":"Describe agent self-registration","security":[],"responses":{"200":{"description":"Registration endpoint documentation","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"registerAgent","summary":"Create an agent account, API key, and starter project","security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterAgentRequest"}}}},"responses":{"201":{"description":"Agent account created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterAgentResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/auth/agent/claim/start":{"post":{"operationId":"startAgentClaim","summary":"Request a short-lived claim code using the autonomous agent’s own key","description":"The person enters the code in Settings while signed in as themselves. Claiming links identities; it does not transfer project ownership or grant access to private projects.","responses":{"200":{"description":"Claim code; keep it private and use it before expiry","content":{"application/json":{"schema":{"type":"object","properties":{"claimCode":{"type":"string","description":"Grouped code formatted XXXX-XXXX-XXXX."},"claimUrl":{"type":"string","format":"uri","description":"Settings claim page with the code already prefilled as ?code=. Hand this to the person; they do not need to retype the code."},"expiresAt":{"type":"string","format":"date-time"}},"required":["claimCode","claimUrl","expiresAt"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Credential is not an agent credential"},"409":{"description":"Agent is already claimed"}}}},"/api/auth/agent/status":{"get":{"operationId":"getAgentStatus","summary":"Verify an agent credential and inspect its claim state","description":"Returns a bounded status for the Bearer credential. It does not expose the accountable person, credential metadata, or private project data.","responses":{"200":{"description":"Active agent credential status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentStatusResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Credential is valid but is not an agent credential"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/auth/agent/invites/redeem":{"post":{"operationId":"redeemAgentInvite","summary":"Join a workspace through a single-use agent invite","description":"Send the opaque token or full invite URL in the request body. With an existing autonomous agent API key, joins as that agent and preserves its identity and current claim state. Delegated agent keys are refused. Without a key, creates a new autonomous agent. The workspace manager creates the invite in Settings using a human session. A token grants member access only. Every success returns organizationApiKey, the workspace-scoped credential this workspace’s projects require; a personal key cannot reach them. Redeeming again returns 200, issues a replacement organizationApiKey, and revokes the previous one.","security":[{"bearerApiKey":[]},{}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":8,"maxLength":500,"writeOnly":true,"description":"The opaque oi_ token or the complete /join/<token> URL shown in Settings."},"name":{"type":"string","minLength":1,"maxLength":100},"agentClient":{"type":"string","minLength":1,"maxLength":40},"contactEmail":{"type":"string","format":"email","description":"Descriptive contact only; never an account login."},"purpose":{"type":"string","maxLength":500}},"required":["token"]}}}},"responses":{"200":{"description":"Already a member; the link remains unused and a replacement organizationApiKey is issued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemAgentInviteResponse"}}}},"201":{"description":"Joined; apiKey is returned only for a newly created agent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemAgentInviteResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/auth/agent/invitations/{id}/accept":{"post":{"operationId":"acceptAgentInvitation","deprecated":true,"summary":"Accept a workspace invitation with the agent’s own API key","description":"The invitation id is the capability: possession of it plus a valid agent credential joins the workspace, because an agent has no deliverable address for Better Auth’s email-match rule. Treat the id like an invite link. The response returns organizationApiKey, the workspace-scoped credential this workspace’s projects require; the agent’s personal key cannot reach them. Accepting again returns 200 with alreadyMember, leaves the invitation untouched, issues a replacement organizationApiKey, and revokes the previous one.","parameters":[{"$ref":"#/components/parameters/AgentInvitationId"}],"responses":{"200":{"description":"Joined, or already a member; a workspace-scoped key is issued either way","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptAgentInvitationResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Invitation does not exist, was already used, or has expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/agent/organizations":{"get":{"operationId":"listAgentOrganizations","summary":"List workspaces the authenticated agent belongs to","description":"Returns memberships for the agent account identified by the Bearer API key. Unclaimed autonomous agents may use this route.","responses":{"200":{"description":"Workspace memberships","content":{"application/json":{"schema":{"type":"object","properties":{"organizations":{"type":"array","items":{"$ref":"#/components/schemas/AgentOrganizationMembership"}}},"required":["organizations"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"operationId":"createAgentOrganization","summary":"Create a workspace owned by the authenticated agent","description":"Creates an ordinary Pascal workspace and an owner membership for the agent account identified by the Bearer API key. Unclaimed autonomous agents may use this route.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentOrganizationRequest"}}}},"responses":{"201":{"description":"Workspace created; the agent is its owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateAgentOrganizationResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"No unique workspace slug could be allocated"}}}},"/api/auth/agent/organizations/invite":{"post":{"operationId":"inviteOrganizationMemberAsAgent","summary":"Invite a person or addressable legacy agent to an agent-managed workspace","description":"The authenticated agent must be an owner or admin of the target workspace. `email` sends a normal invitation to a person. `agentUserId` only works for a legacy agent account that has an identity email; current self-registered agents have no email and receive `agent_has_no_email`. To add one of those agents, a human workspace manager must create a single-use agent invite link in Settings, and the agent redeems it with POST /api/auth/agent/invites/redeem.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteOrganizationMemberRequest"}}}},"responses":{"201":{"description":"Invitation created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InviteOrganizationMemberResponse"}}}},"400":{"description":"Invalid request, or the selected agent has no identity email and must use an invite link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Agent credential lacks permission, or the agent is not an owner/admin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Workspace or target agent not found"},"409":{"description":"Invitee is already a workspace member"},"429":{"description":"Unclaimed agent exceeded the 20-invitations-per-day limit"},"500":{"description":"Invitation could not be created"}}}},"/api/auth/agent/invitations":{"get":{"operationId":"listAgentEmailInvitations","deprecated":true,"summary":"List legacy email-addressed invitations","description":"New agents have no email, so this returns an empty list with a note. Use a workspace-manager-provided agent invite and POST /api/auth/agent/invites/redeem instead.","responses":{"200":{"description":"Invitation list and optional explanation","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/mcp":{"get":{"operationId":"getAgentDiscovery","summary":"Get hosted agent API discovery metadata","description":"Returns hosted MCP and REST + SSE scene API metadata for non-MCP discovery requests.","security":[],"responses":{"200":{"description":"Agent API discovery metadata","content":{"application/json":{"schema":{"type":"object"}}}}}},"post":{"operationId":"handleNativeMcp","summary":"Handle native MCP Streamable HTTP JSON-RPC","description":"Native MCP endpoint for clients such as Claude Code, Cursor, OpenAI Codex, and Windsurf. Use the official MCP client transport rather than hand-written OpenAPI calls when possible.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"MCP JSON-RPC initialize, tools/list, tools/call, resources, or prompts request."}}}},"responses":{"200":{"description":"MCP JSON-RPC or SSE response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"text/event-stream":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/api/scenes":{"get":{"operationId":"listScenes","summary":"List projects/scenes visible to the authenticated user or API key","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}}],"responses":{"200":{"description":"Scene list","content":{"application/json":{"schema":{"type":"object","properties":{"scenes":{"type":"array","items":{"$ref":"#/components/schemas/SceneMeta"}}},"required":["scenes"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"saveSceneToProject","summary":"Save a scene graph to an existing project or starterProjectId","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveSceneRequest"}}}},"responses":{"201":{"description":"Scene saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneMeta"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/scenes/{id}":{"get":{"operationId":"getScene","summary":"Load the current scene graph visible to this credential","parameters":[{"$ref":"#/components/parameters/SceneId"}],"responses":{"200":{"description":"Scene with graph","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneWithGraph"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"replaceScene","summary":"Replace the latest scene graph for a project","parameters":[{"$ref":"#/components/parameters/SceneId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceSceneRequest"}}}},"responses":{"200":{"description":"Scene replaced","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneMeta"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/VersionConflict"}}},"patch":{"operationId":"renameScene","summary":"Rename a project/scene","parameters":[{"$ref":"#/components/parameters/SceneId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameSceneRequest"}}}},"responses":{"200":{"description":"Scene renamed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SceneMeta"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/VersionConflict"}}},"delete":{"operationId":"deleteScene","summary":"Soft-delete or empty a project/scene","parameters":[{"$ref":"#/components/parameters/SceneId"}],"responses":{"204":{"description":"Scene deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/VersionConflict"}}}},"/api/scenes/{id}/events":{"get":{"operationId":"streamSceneEvents","summary":"Open an SSE stream for scene events","parameters":[{"$ref":"#/components/parameters/SceneId"},{"name":"after","in":"query","required":false,"schema":{"type":"integer","minimum":0}}],"responses":{"200":{"description":"Text/event-stream response","content":{"text/event-stream":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/scenes/{id}/publish":{"post":{"operationId":"publishScene","summary":"Save the draft as a version when it changed, publish the latest saved version, and bake its 3D file","description":"The editor’s Save & publish. The project’s privacy is left as it is: a private project stays private. The 3D file bakes after the publish; read it from `GET /api/scenes/{id}/glb`.","parameters":[{"$ref":"#/components/parameters/SceneId"}],"responses":{"200":{"description":"Published","content":{"application/json":{"schema":{"type":"object","required":["publishedVersion","didSaveVersion","didPublishVersion"],"properties":{"publishedVersion":{"type":"integer","nullable":true},"didSaveVersion":{"type":"boolean"},"didPublishVersion":{"type":"boolean","description":"False when the latest saved version was already published."}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The project cannot be published as it is (`cannot_publish`): an empty scene, or nothing saved to publish.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/scenes/{id}/glb":{"get":{"operationId":"getPublishedSceneGlb","summary":"Download the published version’s 3D file (GLB, full detail)","description":"Every answer but the 404 carries `X-Pascal-Version`, the published version it is about. Poll while it answers 202.","parameters":[{"$ref":"#/components/parameters/SceneId"}],"responses":{"202":{"description":"The 3D file is baking (`{ status: \"pending\", version }`)"},"307":{"description":"Ready: `Location` is a short-lived signed URL of the GLB (textures embedded as KTX2)."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"`not_found` (no project, or the credential may not download its 3D files), `not_published`, or `{ status: \"unavailable\", version }` when that version has no 3D file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The bake failed (`{ status: \"failed\", version }`)."}}}},"/api/v1/models":{"get":{"operationId":"listArchitectModels","summary":"List the Architect models","description":"OpenAI-compatible model list. Any OpenAI SDK, or the AI SDK’s OpenAI providers, pointed at `{server}/api/v1` call the Architect, Pascal’s scene-building model, as they call a reasoning model. Empty on a deployment with no executor to run a turn.","tags":["Architect"],"responses":{"200":{"description":"Model list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectModelList"}}}},"401":{"$ref":"#/components/responses/ArchitectError"}}}},"/api/v1/models/{id}":{"get":{"operationId":"retrieveArchitectModel","summary":"Retrieve an Architect model","tags":["Architect"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectModel"}}}},"401":{"$ref":"#/components/responses/ArchitectError"},"404":{"$ref":"#/components/responses/ArchitectError"},"503":{"$ref":"#/components/responses/ArchitectError"}}}},"/api/v1/chat/completions":{"post":{"operationId":"createArchitectChatCompletion","summary":"Run an Architect turn (Chat Completions)","description":"OpenAI Chat Completions over one turn of the Architect on a project. The turn builds and edits the project’s scene. The reply is `content`; the readable reasoning (the model’s thinking and one line per step) is `reasoning_content`; a turn that changed the scene is saved as a named version, cited as a `url_citation` in `annotations` and named in `metadata.pascal_version*`. The last user message is the request, with its `image_url` and `file` parts; earlier messages the project’s conversation already holds are not repeated, and `system` and `developer` messages become instructions for this turn. With `stream: true` the response is a `text/event-stream` of `chat.completion.chunk` events (`delta.reasoning_content`, `delta.content`, the annotation on the last chunk, a usage chunk with `stream_options.include_usage`) ending with `data: [DONE]`, with `: keepalive` comments during silences. A turn can run for minutes; closing the connection stops it. Without `stream`, the headers leave within 15 s and spaces keep the connection open until the JSON body, so a turn that fails after that answers 200 with the error as the body. A question the Architect asks is the reply, and the next request answers it: `1`, `2`… picks an option. `metadata.commit_message` names the version the turn saves; `metadata.pascal_max_credits` caps the credits the turn may spend, and a turn that reaches it ends with `finish_reason: \"length\"`. Errors carry `x-should-retry: false`: a turn that started may already have edited the scene. A turn needs at least one credit in the project’s credit pool.","tags":["Architect"],"parameters":[{"$ref":"#/components/parameters/ArchitectProject"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectChatCompletionRequest"}}}},"responses":{"200":{"description":"Completion, or a server-sent event stream of `chat.completion.chunk` events when `stream` is true","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectChatCompletion"}},"text/event-stream":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/ArchitectError"},"401":{"$ref":"#/components/responses/ArchitectError"},"402":{"$ref":"#/components/responses/ArchitectInsufficientCredits"},"404":{"$ref":"#/components/responses/ArchitectError"},"409":{"$ref":"#/components/responses/ArchitectError"},"503":{"$ref":"#/components/responses/ArchitectError"}}}},"/api/v1/responses":{"post":{"operationId":"createArchitectResponse","summary":"Run an Architect turn (Responses)","description":"OpenAI Responses over one turn of the Architect on a project, with the same authentication, project header, models and files as chat completions. `input` is a string or message items, with `input_text`, `input_image` and `input_file` parts; `instructions` are instructions for this turn. The output is the reply as `message` items and the readable reasoning as `reasoning` items with `summary_text` parts. A turn that changed the scene is saved as one named version: `metadata.pascal_version`, `pascal_version_label` and `pascal_version_url`, and a `url_citation` annotation at the end of the reply. A turn that asked a question has `metadata.pascal_waiting: \"question\"`; the next request answers it (`1`, `2`… picks an option). `metadata.commit_message` names the version; `metadata.pascal_max_credits` caps the credits the turn may spend, and a turn that reaches it ends `incomplete` (`incomplete_details.reason: \"max_credits\"`). `previous_response_id` continues the project’s conversation and must belong to the project’s active conversation. With `stream: true` the response is a `text/event-stream` of Responses events (`response.created` through `response.completed`, `response.incomplete` or `response.failed`), with `: keepalive` comments during silences. Without `stream`, the headers leave within 15 s and spaces keep the connection open until the JSON body. A turn that fails after it started answers 200 with `status: \"failed\"` (`\"cancelled\"` once stopped): it is never retried, since it may already have edited the scene. A synchronous request follows its turn for at most 13 minutes: a turn still running then is stopped (`status: \"failed\"`), except an architect-pro turn, which runs on and answers `status: \"in_progress\"` (a stream ends with an `error` event, `turn_still_running`): poll `GET /api/v1/responses/{id}`. A turn that may run longer is sent with `background: true`, at any model: the request answers `status: \"queued\"` at once, the turn runs to its end with nobody following (credits charged and the version saved as for a followed turn), and `GET /api/v1/responses/{id}` reads it; `POST /api/v1/responses/{id}/cancel` stops it.","tags":["Architect"],"parameters":[{"$ref":"#/components/parameters/ArchitectProject"},{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectResponseRequest"}}}},"responses":{"200":{"description":"Response object, or a server-sent event stream when `stream` is true","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectResponse"}},"text/event-stream":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/ArchitectError"},"401":{"$ref":"#/components/responses/ArchitectError"},"402":{"$ref":"#/components/responses/ArchitectInsufficientCredits"},"404":{"$ref":"#/components/responses/ArchitectError"},"409":{"$ref":"#/components/responses/ArchitectError"},"429":{"$ref":"#/components/responses/ArchitectRateLimited"},"503":{"$ref":"#/components/responses/ArchitectError"}}}},"/api/v1/responses/{id}":{"get":{"operationId":"retrieveArchitectResponse","summary":"Retrieve an Architect response","description":"A response’s current state: the reply and reasoning as they streamed, the context it was created with (model, instructions, metadata, `previous_response_id`, `background`), its status and usage, and once it completed the version it saved. The whole turn: a request that answered its question continues the same response. Readable by anyone who may edit the project; reading changes nothing.","tags":["Architect"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Response object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectResponse"}}}},"401":{"$ref":"#/components/responses/ArchitectError"},"404":{"$ref":"#/components/responses/ArchitectError"}}}},"/api/v1/responses/{id}/cancel":{"post":{"operationId":"cancelArchitectResponse","summary":"Cancel an Architect turn","description":"Stops a turn the way the editor’s Stop does, a turn waiting on its question included. A turn already over answers as it ended. Only the person who started it may: anyone else gets 404 `turn_not_found`, as for an id that doesn’t exist.","tags":["Architect"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Response object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectResponse"}}}},"401":{"$ref":"#/components/responses/ArchitectError"},"404":{"$ref":"#/components/responses/ArchitectError"},"429":{"$ref":"#/components/responses/ArchitectRateLimited"}}}},"/api/v1/files":{"post":{"operationId":"createArchitectFile","summary":"Upload a file for the Architect","description":"OpenAI `files.create`: a multipart upload stored as one of the project’s files. Its id (`file-…`) goes in `input_file`, `input_image` or chat `file` parts. Images, PDFs, and the DXF, CSV and DAE plans architect-pro reads; the request body is capped at about 4.5 MB.","tags":["Architect"],"parameters":[{"$ref":"#/components/parameters/ArchitectProject"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"},"purpose":{"type":"string"}},"required":["file"]}}}},"responses":{"200":{"description":"File object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectFile"}}}},"400":{"$ref":"#/components/responses/ArchitectError"},"401":{"$ref":"#/components/responses/ArchitectError"},"404":{"$ref":"#/components/responses/ArchitectError"}}},"get":{"operationId":"listArchitectFiles","summary":"List the project’s files","tags":["Architect"],"parameters":[{"$ref":"#/components/parameters/ArchitectProject"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000}},{"name":"after","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"File list, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ArchitectFile"}},"has_more":{"type":"boolean"}},"required":["object","data","has_more"]}}}},"400":{"$ref":"#/components/responses/ArchitectError"},"401":{"$ref":"#/components/responses/ArchitectError"},"404":{"$ref":"#/components/responses/ArchitectError"}}}},"/api/v1/files/{id}":{"get":{"operationId":"retrieveArchitectFile","summary":"Retrieve a file","tags":["Architect"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"File object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectFile"}}}},"401":{"$ref":"#/components/responses/ArchitectError"},"404":{"$ref":"#/components/responses/ArchitectError"}}}}},"components":{"securitySchemes":{"bearerApiKey":{"type":"http","scheme":"bearer","bearerFormat":"Pascal API key","description":"Use `Authorization: Bearer sk_live_...` or `Authorization: Bearer sk_test_...`."}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"Any unique string (1 to 255 printable ASCII characters, e.g. a UUID). Sent again with the same request within 24 hours, by the same person on the same project, it answers with the turn the first request started, as it stands now (`Idempotent-Replayed: true`), instead of starting another. With a different request it is refused, 409 `idempotency_mismatch`.","schema":{"type":"string","minLength":1,"maxLength":255}},"ArchitectProject":{"name":"X-Pascal-Project","in":"header","required":false,"description":"Id of the project the Architect works on; it must be editable with the key. Required unless `metadata.project_id` is sent (for Responses, `previous_response_id` also supplies it).","schema":{"type":"string","minLength":1}},"SceneId":{"name":"id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64}},"AgentInvitationId":{"name":"id","in":"path","required":true,"description":"Invitation id from the workspace manager. A bearer capability; keep it out of logs.","schema":{"type":"string","minLength":1,"maxLength":64}}},"responses":{"ArchitectError":{"description":"OpenAI-shaped error with a `doc_url` (https://editor.pascal.app/docs/developers/api#errors) and `x-should-retry: false`. Every answer carries `Request-Id`. 400 `invalid_input`, `no_project` or `unsupported_parameter`, with its `param`; 401 `invalid_api_key`; 403 `upgrade_required`; 404 `turn_not_found`, `project_not_found`, `file_not_found` or `model_not_found` (an id the key can’t read is answered as one that doesn’t exist); 409 `turn_in_progress` (naming the running `response_id`), `question_waiting`, `previous_response_not_active` or `idempotency_mismatch`; 500 `internal_error`, naming the request id; 503 `executor_unavailable` on a deployment with no executor. The retryable errors are 429 `rate_limit_exceeded` and a `background` launch that failed before its turn ran (502, without the header).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectErrorBody"}}}},"ArchitectRateLimited":{"description":"Too many requests with this key: nothing ran. Retry after the `Retry-After` seconds; `x-should-retry: true`.","headers":{"Retry-After":{"schema":{"type":"integer","minimum":1}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectErrorBody"}}}},"ArchitectInsufficientCredits":{"description":"The project’s credit pool (its workspace’s, else the key owner’s) cannot fund a turn. Returned before the turn starts, with `type` and `code` `insufficient_quota`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArchitectErrorBody"}}}},"BadRequest":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid API key/session","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Authenticated credential is not permitted to perform this operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Scene or project not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded. Retry after the `Retry-After` seconds; `RateLimit` and `RateLimit-Policy` report the budget on every Scene API response.","headers":{"Retry-After":{"schema":{"type":"integer","minimum":1}},"RateLimit":{"schema":{"type":"string"}},"RateLimit-Policy":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InternalError":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"VersionConflict":{"description":"Optimistic concurrency conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"schemas":{"AgentStatusResponse":{"type":"object","additionalProperties":false,"properties":{"schemaVersion":{"type":"integer","const":1},"agentId":{"type":"string"},"mode":{"type":"string","enum":["autonomous","delegated"]},"claimed":{"type":"boolean","description":"False only for an unclaimed autonomous agent. Delegated agents already act for a person."},"organizationScoped":{"type":"boolean"}},"required":["schemaVersion","agentId","mode","claimed","organizationScoped"]},"RegisterAgentRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"purpose":{"type":"string","maxLength":500},"agentClient":{"type":"string","enum":["claude-code","chatgpt","cursor","openai-codex","openclaw","windsurf","other"]}},"required":["name"]},"RegisterAgentResponse":{"type":"object","properties":{"userId":{"type":"string","description":"Agent account subject; has no email or browser session."},"agentId":{"type":"string","description":"Persistent agent identity; retain across reconnects."},"apiKey":{"type":"string"},"starterProjectId":{"type":"string"},"sceneApiUrl":{"type":"string","format":"uri"},"mcpEndpoint":{"type":"string","format":"uri"},"openApiUrl":{"type":"string","format":"uri"},"docsUrl":{"type":"string","format":"uri"},"sandbox":{"type":"object","properties":{"claimed":{"type":"boolean","const":false},"allowed":{"type":"array","items":{"type":"string"}},"notYetReachableWithAnApiKey":{"type":"array","items":{"type":"string"}},"blockedUntilClaimed":{"type":"array","items":{"type":"string"}},"howToClaim":{"type":"string"}},"required":["claimed","allowed","notYetReachableWithAnApiKey","blockedUntilClaimed","howToClaim"]},"usage":{"type":"object","properties":{"setApiKey":{"type":"string"},"claudeCode":{"type":"string","description":"User-scoped Claude Code setup command. Requires PASCAL_API_KEY to be set first."},"listScenes":{"type":"string"},"getStarterScene":{"type":"string"},"openApi":{"type":"string"},"status":{"type":"string"},"startClaim":{"type":"string"},"createOrganization":{"type":"string"},"redeemInvite":{"type":"string"}},"required":["setApiKey","claudeCode","listScenes","getStarterScene","openApi","status","startClaim","createOrganization","redeemInvite"]},"setup":{"type":"object","properties":{"apiKeyEnvironmentVariable":{"type":"string"},"claudeCodeCredentialStorage":{"type":"string"},"shellHistory":{"type":"string"}},"required":["apiKeyEnvironmentVariable","claudeCodeCredentialStorage","shellHistory"]},"message":{"type":"string"}},"required":["userId","agentId","apiKey","starterProjectId","sceneApiUrl","mcpEndpoint","openApiUrl","docsUrl","sandbox","usage","setup","message"]},"AgentOrganization":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"}},"required":["id","name","slug"]},"RedeemAgentInviteResponse":{"type":"object","properties":{"userId":{"type":"string"},"agentId":{"type":"string","description":"Persistent agent identity."},"alreadyMember":{"type":"boolean","const":true,"description":"Present only on the 200 repeat response. The invite link stays unused."},"apiKey":{"type":"string","description":"The agent’s own personal key, returned only when this call created the account. It is not scoped to the workspace and its projects will refuse it."},"organizationApiKey":{"type":"string","description":"Workspace-scoped key, shown once. Required for this workspace’s projects; redeeming again replaces it and revokes the previous one."},"organization":{"$ref":"#/components/schemas/AgentOrganization"},"role":{"type":"string","const":"member"},"sandbox":{"type":"object","properties":{"claimed":{"type":"boolean"}},"required":["claimed"]}},"required":["userId","agentId","organizationApiKey","organization","role","sandbox"]},"AcceptAgentInvitationResponse":{"type":"object","properties":{"joined":{"type":"boolean","const":true},"alreadyMember":{"type":"boolean","const":true,"description":"Present only when the membership already existed. The invitation stays pending."},"organizationApiKey":{"type":"string","description":"Workspace-scoped key, shown once. Required for this workspace’s projects; accepting again replaces it and revokes the previous one."},"organization":{"$ref":"#/components/schemas/AgentOrganization"},"role":{"type":"string","description":"Role from the invitation, or the existing one."},"message":{"type":"string"}},"required":["joined","organizationApiKey","organization","role","message"]},"AgentOrganizationMembership":{"allOf":[{"$ref":"#/components/schemas/AgentOrganization"},{"type":"object","properties":{"role":{"type":"string"}},"required":["role"]}]},"CreateAgentOrganizationRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"slug":{"type":"string","minLength":2,"maxLength":60,"pattern":"^[a-z0-9-]+$","description":"Optional lowercase URL slug. If omitted, Pascal derives one from the name and retries collisions with a suffix."}},"required":["name"]},"CreateAgentOrganizationResponse":{"type":"object","properties":{"organization":{"$ref":"#/components/schemas/AgentOrganization"},"role":{"type":"string","const":"owner"},"next":{"type":"object","additionalProperties":{"type":"string"}},"message":{"type":"string"}},"required":["organization","role","next","message"]},"InviteOrganizationMemberRequest":{"type":"object","properties":{"organizationId":{"type":"string"},"email":{"type":"string","format":"email","description":"Email address of a person who can accept through the browser."},"agentUserId":{"type":"string","description":"User id of a legacy agent with an identity email. New self-registered agents are email-less and must use a human-manager-created invite link instead."},"role":{"type":"string","enum":["member","admin"],"default":"member"}},"required":["organizationId"],"oneOf":[{"required":["email"],"not":{"required":["agentUserId"]}},{"required":["agentUserId"],"not":{"required":["email"]}}]},"InviteOrganizationMemberResponse":{"type":"object","properties":{"invitationId":{"type":"string"},"invitee":{"type":"string","enum":["person","agent"]},"role":{"type":"string","enum":["member","admin"]},"expiresAt":{"type":"string","format":"date-time"},"acceptUrl":{"type":"string","format":"uri"},"message":{"type":"string"}},"required":["invitationId","invitee","role","expiresAt","acceptUrl","message"]},"SceneMeta":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"projectId":{"type":["string","null"]},"ownerId":{"type":["string","null"]},"thumbnailUrl":{"type":["string","null"],"format":"uri"},"version":{"type":"integer","minimum":0},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"sizeBytes":{"type":"integer","minimum":0},"nodeCount":{"type":"integer","minimum":0}},"required":["id","name","projectId","ownerId","version","createdAt","updatedAt"]},"SceneWithGraph":{"allOf":[{"$ref":"#/components/schemas/SceneMeta"},{"type":"object","properties":{"graph":{"$ref":"#/components/schemas/SceneGraph"}},"required":["graph"]}]},"SceneGraph":{"type":"object","properties":{"nodes":{"type":"object","additionalProperties":true,"description":"Pascal scene nodes keyed by node id. Runtime-validated with AnyNode."},"rootNodeIds":{"type":"array","items":{"type":"string"}},"collections":{"type":"object","additionalProperties":true},"installedPlugins":{"type":"array","items":{"type":"string"}},"materials":{"type":"object","additionalProperties":true}},"required":["nodes","rootNodeIds"]},"SaveSceneRequest":{"type":"object","properties":{"id":{"type":"string","description":"Existing project id. For agent registration, use starterProjectId."},"projectId":{"type":["string","null"]},"name":{"type":"string","minLength":1,"maxLength":200},"graph":{"$ref":"#/components/schemas/SceneGraph"},"thumbnailUrl":{"type":["string","null"],"format":"uri"}},"required":["name","graph"]},"ReplaceSceneRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"graph":{"$ref":"#/components/schemas/SceneGraph"},"thumbnailUrl":{"type":["string","null"],"format":"uri"},"expectedVersion":{"type":"integer","minimum":0}},"required":["graph"]},"RenameSceneRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"expectedVersion":{"type":"integer","minimum":0}},"required":["name"]},"ArchitectModel":{"type":"object","properties":{"id":{"type":"string","enum":["architect","architect-low","architect-medium","architect-high","architect-pro","pascal-architect","pascal-architect-low","pascal-architect-medium","pascal-architect-high","pascal-architect-pro"]},"object":{"type":"string","const":"model"},"created":{"type":"integer"},"owned_by":{"type":"string"}},"required":["id","object","created","owned_by"]},"ArchitectModelList":{"type":"object","properties":{"object":{"type":"string","const":"list"},"data":{"type":"array","items":{"$ref":"#/components/schemas/ArchitectModel"}}},"required":["object","data"]},"ArchitectErrorBody":{"type":"object","properties":{"error":{"type":"object","properties":{"message":{"type":"string"},"type":{"type":"string","description":"`invalid_request_error`, `authentication_error`, `conflict_error`, `idempotency_error`, `insufficient_quota`, `rate_limit_error`, `api_error` or `server_error`."},"code":{"type":["string","null"],"description":"`invalid_input`, `no_project`, `unsupported_parameter`, `invalid_api_key`, `insufficient_quota`, `upgrade_required`, `turn_not_found`, `project_not_found`, `file_not_found`, `model_not_found`, `turn_in_progress`, `question_waiting`, `previous_response_not_active`, `idempotency_mismatch`, `rate_limit_exceeded`, `internal_error`, `executor_unavailable`; in a turn’s own `error`, also `turn_still_running` or `cancelled`."},"param":{"type":["string","null"]},"doc_url":{"type":"string","format":"uri","description":"Where this code is explained."},"response_id":{"type":["string","null"],"description":"The running turn, on `turn_in_progress`."}},"required":["message","type"]}},"required":["error"]},"ArchitectUsage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"},"completion_tokens_details":{"type":"object","properties":{"reasoning_tokens":{"type":"integer"}}},"total_tokens":{"type":"integer"}}},"ArchitectContentPart":{"type":"object","description":"Text (`text`, `input_text`) or a file: Responses `input_image` (`image_url` as a data URL or a project file’s storage URL, or `file_id`) and `input_file` (`file_data` as a data URL or base64 with `filename`, `file_url`, or `file_id`); Chat Completions `image_url` (`image_url.url`) and `file` (`file.file_data` with `file.filename`, or `file.file_id`). File ids are `file-…` from `POST /api/v1/files`. Other URLs are not fetched. Images and PDFs at every effort; DXF, CSV and DAE only with architect-pro.","properties":{"type":{"type":"string"}},"required":["type"]},"ArchitectPascalMetadata":{"type":"object","description":"The turn’s outcome, beside the caller’s own string metadata: `pascal_project_id`; `pascal_version`, `pascal_version_label` and `pascal_version_url` when the turn saved a version (the project’s saved version, not the Architect’s); `pascal_waiting: \"question\"` when the next request answers the Architect’s question. Every turn also names the Architect that answered: `pascal_architect_version`, one number for every `architect-*` model (\"1.0\"; a minor step when its prompts, tools or orchestration change, a major step for a new generation), and `pascal_release`, the deployed commit it ran from (absent when the deployment has none).","additionalProperties":{"type":"string"}},"ArchitectUrlCitation":{"type":"object","description":"The version the turn saved, at the end of the reply.","properties":{"type":{"type":"string","const":"url_citation"},"start_index":{"type":"integer"},"end_index":{"type":"integer"},"title":{"type":"string","description":"\"Version 7: 1 room added\""},"url":{"type":"string"}}},"ArchitectChatCompletionRequest":{"type":"object","properties":{"model":{"type":"string","enum":["architect","architect-low","architect-medium","architect-high","architect-pro","pascal-architect","pascal-architect-low","pascal-architect-medium","pascal-architect-high","pascal-architect-pro"],"description":"The Architect, at an effort: how much of a whole building it builds, each adding to the one below (low, a layout you can walk through; medium, its structure and details; high, the outside, lights and finishes; pro, everything). `architect` uses `reasoning_effort` (default medium); a suffix fixes it. Every id also answers with a `pascal-` prefix (`pascal-architect`, `pascal-architect-high`…)."},"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["system","developer","user","assistant"]},"content":{"description":"Text, or content parts.","oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ArchitectContentPart"}}]}},"required":["role","content"]},"minItems":1},"stream":{"type":"boolean","description":"Stream `chat.completion.chunk` events as server-sent events."},"stream_options":{"type":"object","properties":{"include_usage":{"type":"boolean"}}},"reasoning_effort":{"type":"string","enum":["minimal","low","medium","high","pro"]},"metadata":{"type":"object","properties":{"project_id":{"type":"string"},"pascal_max_credits":{"type":"string","pattern":"^\\d+(\\.\\d+)?$","examples":["50"],"description":"The most Pascal credits this turn may spend, a number above 0 sent as a string like every metadata value. No cap when absent; an invalid value is a 400. When the turn reaches it, it ends `incomplete` with `incomplete_details.reason: \"max_credits\"` (chat: `finish_reason: \"length\"`), and what it changed so far is saved as a version as usual. An architect-pro turn admits a model call only if its worst case fits under the cap, so its model calls never take it over; the time of the sandbox running its tools is billed after the fact and can. Every other turn is checked between its rounds of scene tools: once it has spent the cap it stops before the next round, so it can end above the cap by what its last round of model steps cost. A request that answers a question continues the turn under the cap the turn started with."}},"description":"`project_id` is an alternative to the `X-Pascal-Project` header; `pascal_max_credits` caps the credits the turn may spend."}},"required":["model","messages"]},"ArchitectChatCompletion":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"chat.completion"},"created":{"type":"integer"},"model":{"type":"string"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"finish_reason":{"type":"string","description":"`stop`, or `length` for a turn that stopped short."},"message":{"type":"object","properties":{"role":{"type":"string","const":"assistant"},"content":{"type":"string"},"reasoning_content":{"type":"string"},"annotations":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","const":"url_citation"},"url_citation":{"$ref":"#/components/schemas/ArchitectUrlCitation"}}}}},"required":["role","content"]}}}},"metadata":{"$ref":"#/components/schemas/ArchitectPascalMetadata"},"usage":{"$ref":"#/components/schemas/ArchitectUsage"}},"required":["id","object","created","model","choices","usage"]},"ArchitectResponseRequest":{"type":"object","properties":{"model":{"type":"string","enum":["architect","architect-low","architect-medium","architect-high","architect-pro","pascal-architect","pascal-architect-low","pascal-architect-medium","pascal-architect-high","pascal-architect-pro"]},"input":{"description":"A string, or message items (`{ role, content }`).","oneOf":[{"type":"string"},{"type":"array","items":{"type":"object","properties":{"role":{"type":"string"},"content":{"oneOf":[{"type":"string"},{"type":"array","items":{"$ref":"#/components/schemas/ArchitectContentPart"}}]}}}}]},"instructions":{"type":"string"},"previous_response_id":{"type":"string"},"reasoning":{"type":"object","properties":{"effort":{"type":"string","enum":["minimal","low","medium","high","pro"]}}},"stream":{"type":"boolean"},"background":{"type":"boolean","description":"Return at once (`status: \"queued\"`) and run the turn with nobody following; poll `GET /api/v1/responses/{id}`. Any model."},"metadata":{"type":"object","properties":{"project_id":{"type":"string"},"pascal_max_credits":{"type":"string","pattern":"^\\d+(\\.\\d+)?$","examples":["50"],"description":"The most Pascal credits this turn may spend, a number above 0 sent as a string like every metadata value. No cap when absent; an invalid value is a 400. When the turn reaches it, it ends `incomplete` with `incomplete_details.reason: \"max_credits\"` (chat: `finish_reason: \"length\"`), and what it changed so far is saved as a version as usual. An architect-pro turn admits a model call only if its worst case fits under the cap, so its model calls never take it over; the time of the sandbox running its tools is billed after the fact and can. Every other turn is checked between its rounds of scene tools: once it has spent the cap it stops before the next round, so it can end above the cap by what its last round of model steps cost. A request that answers a question continues the turn under the cap the turn started with."}},"additionalProperties":{"type":"string"},"description":"Echoed on the response. `project_id` is an alternative to the `X-Pascal-Project` header; `pascal_max_credits` caps the credits the turn may spend."}},"required":["model","input"]},"ArchitectResponse":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"response"},"created_at":{"type":"integer"},"status":{"type":"string","enum":["queued","in_progress","completed","incomplete","failed","cancelled"]},"model":{"type":"string"},"output":{"type":"array","description":"`reasoning` items (`summary` of `summary_text` parts: the model’s thinking and one bold line per step) and `message` items (`output_text` with the version’s `url_citation` at the end).","items":{"type":"object"}},"output_text":{"type":"string"},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"type":{"type":"string"},"param":{"type":["string","null"]}}},"incomplete_details":{"type":["object","null"],"properties":{"reason":{"type":"string","enum":["balance","max_credits","time_limit"],"description":"`balance`: the credit pool could not fund the next step; `max_credits`: the turn reached `metadata.pascal_max_credits`; `time_limit`: it ran out of time."}}},"metadata":{"$ref":"#/components/schemas/ArchitectPascalMetadata"},"usage":{"type":["object","null"]}},"required":["id","object","status","model","output"]},"ArchitectFile":{"type":"object","properties":{"id":{"type":"string","description":"`file-<asset id>`"},"object":{"type":"string","const":"file"},"bytes":{"type":"integer"},"created_at":{"type":"integer"},"filename":{"type":"string"},"purpose":{"type":"string","const":"user_data"},"status":{"type":"string","const":"processed"}},"required":["id","object","bytes","created_at","filename","purpose","status"]},"Error":{"type":"object","properties":{"error":{"type":"string","description":"Machine-readable error code."},"message":{"type":"string"},"hint":{"type":"string","description":"What to do next, when there is a known fix."},"details":{}},"required":["error"]}}}}