{"openapi":"3.1.0","info":{"title":"Faces API","version":"1.0","description":"Faces API for creating and managing presentations. Generate presentations from prompts, or read and write individual slides. Each slide is a React component (face.tsx) with content blocks (face.content.json) and editor controls (face.controls.json)."},"servers":[{"url":"https://faces.app/api/v1","description":"API v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key with \"faces_\" prefix. Create one at Settings > Developers."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"hint":{"type":"string"}},"required":["error"]},"ProjectConfig":{"type":"object","properties":{"layout":{"type":"string","enum":["REGULAR","CARD","SLIDES","SLIDESHOW","STACKED"]},"slidesDisplay":{"type":"string","enum":["CARDS","FULLSCREEN"]},"stackedOrientation":{"type":"string","enum":["VERTICAL","HORIZONTAL"]},"cardsSlidesPerView":{"type":"number","minimum":0.5,"maximum":2},"cardsBackgroundColor":{"type":"string"},"cardsBackgroundImage":{"type":"string"},"cardsCorners":{"type":"string","enum":["ROUND","SQUARE"]},"showBrandLogo":{"type":"boolean"},"width":{"type":"string","enum":["FULL","MEDIUM","COMPACT"]},"mobileCanvas":{"type":"string","enum":["LEGACY","COMPACT"]},"theme":{"type":"object","properties":{"fontFamily":{"type":"string"},"headingFontFamily":{"type":"string"},"radius":{"type":"string"},"colors":{"type":"object","properties":{"default":{"type":"object","properties":{"background":{"type":"string"},"foreground":{"type":"string"},"card":{"type":"string"},"card-foreground":{"type":"string"},"card-border":{"type":"string"},"primary":{"type":"string"},"primary-foreground":{"type":"string"},"secondary":{"type":"string"},"secondary-foreground":{"type":"string"},"muted":{"type":"string"},"muted-foreground":{"type":"string"},"accent":{"type":"string"},"accent-foreground":{"type":"string"},"destructive":{"type":"string"},"destructive-foreground":{"type":"string"},"border":{"type":"string"},"input":{"type":"string"},"chart-1":{"type":"string"},"chart-2":{"type":"string"},"chart-3":{"type":"string"},"chart-4":{"type":"string"},"chart-5":{"type":"string"}},"required":["background","foreground","card","card-foreground","primary","primary-foreground","secondary","secondary-foreground","muted","muted-foreground","accent","accent-foreground","destructive","destructive-foreground","border","input"]},"dark":{"type":"object","properties":{"background":{"type":"string"},"foreground":{"type":"string"},"card":{"type":"string"},"card-foreground":{"type":"string"},"card-border":{"type":"string"},"primary":{"type":"string"},"primary-foreground":{"type":"string"},"secondary":{"type":"string"},"secondary-foreground":{"type":"string"},"muted":{"type":"string"},"muted-foreground":{"type":"string"},"accent":{"type":"string"},"accent-foreground":{"type":"string"},"destructive":{"type":"string"},"destructive-foreground":{"type":"string"},"border":{"type":"string"},"input":{"type":"string"},"chart-1":{"type":"string"},"chart-2":{"type":"string"},"chart-3":{"type":"string"},"chart-4":{"type":"string"},"chart-5":{"type":"string"}},"required":["background","foreground","card","card-foreground","primary","primary-foreground","secondary","secondary-foreground","muted","muted-foreground","accent","accent-foreground","destructive","destructive-foreground","border","input"]}},"required":["default"]}},"required":["fontFamily","radius","colors"]},"tokens":{"type":"object","properties":{"palette":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","pattern":"^--[a-z][a-z0-9-]*$"},"value":{"type":"string","pattern":"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"}},"required":["name","value"]},"default":[]},"fonts":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","pattern":"^--font-[a-z][a-z0-9-]*$"},"family":{"type":"string","minLength":1},"url":{"type":"string","format":"uri"}},"required":["name","family"]},"default":[]}}}},"description":"Project-level settings stored in project.config.json, including the shared design system. Color token names must start with --; font token names with --font-."}},"parameters":{}},"paths":{"/projects/generate":{"post":{"operationId":"generateProject","summary":"Generate a project","description":"Generate a new project from a text prompt using AI. Returns a job ID to poll with Get job status until it completes.","tags":["Projects"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"prompt":{"type":"string","minLength":1,"description":"A detailed description of the project to generate.","example":"5-slide pitch deck about AI in healthcare with a modern dark theme"},"templateId":{"type":"string","description":"ID of one of your team's templates to base the project on. The template's design is preserved exactly and its slides are reproduced with your content. Only team templates are supported."},"referenceImageUrls":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":20,"description":"Public image URLs to use as visual inspiration."},"model":{"type":"string","enum":["google/gemini-3.6-flash","openai/gpt-5.6-sol:xhigh"],"description":"Generation model. Defaults to Gemini 3.6 Flash."}},"required":["prompt"]}}}},"responses":{"200":{"description":"Job created","content":{"application/json":{"schema":{"type":"object","properties":{"jobId":{"type":"string","description":"Poll this ID with the status endpoint."},"status":{"type":"string","enum":["processing","completed","failed"]},"editorUrl":{"type":["string","null"],"format":"uri","description":"URL to open the project in the Faces editor."},"estimatedDuration":{"type":"string","description":"Estimated generation time. ~120s with a team template, 240s from scratch.","example":"240 seconds"},"projectId":{"type":["string","null"]},"projectSlug":{"type":["string","null"]},"templateId":{"type":"string"}},"required":["jobId","status","editorUrl","estimatedDuration","projectId","projectSlug"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication required","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Insufficient credits to start a generation","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Template not found or not accessible","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded (50 requests per minute)","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Generation could not be dispatched","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/jobs/{jobId}":{"get":{"operationId":"getJobStatus","summary":"Get job status","description":"Check the status of a project generation job. Poll until status is completed or failed.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"The job ID returned by generateProject."},"required":true,"name":"jobId","in":"path"}],"responses":{"200":{"description":"Job status","content":{"application/json":{"schema":{"type":"object","properties":{"jobId":{"type":"string"},"status":{"type":"string","enum":["processing","completed","failed"]},"editorUrl":{"type":["string","null"],"format":"uri"},"projectId":{"type":["string","null"]},"projectSlug":{"type":["string","null"]},"teamId":{"type":["string","null"]},"finalDuration":{"type":"string","description":"Actual generation time. Only present when status is completed.","example":"45 seconds"},"publishedUrl":{"type":"string","format":"uri","description":"Available when status is completed."},"error":{"type":"string","description":"Error message when status is failed."},"createdAt":{"type":"string","format":"date-time"}},"required":["jobId","status","editorUrl","projectId","projectSlug","teamId","createdAt"]}}}},"404":{"description":"Job not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects":{"post":{"operationId":"createProject","summary":"Create a blank project","description":"Create a new empty project. The project is created under the team your API key is scoped to (you choose this when creating the key). Returns the projectSlug and editorUrl. Add slides with createSlides + updateSlide.","tags":["Projects"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Optional display name. Defaults to 'Untitled'."}}}}}},"responses":{"200":{"description":"Project created","content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string"},"projectSlug":{"type":"string"},"projectVersionId":{"type":"string"},"editorUrl":{"type":"string","format":"uri"}},"required":["projectId","projectSlug","projectVersionId","editorUrl"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Authentication required","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listProjects","summary":"List projects","description":"List projects you can access — owned, team-shared with a team you belong to, or shared with you as a collaborator. Supports cursor-based pagination.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["true","false"],"description":"Filter by published status."},"required":false,"name":"published","in":"query"},{"schema":{"type":"number","minimum":1,"maximum":100,"default":20,"description":"Max results per page."},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Pagination cursor from a previous response."},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Project list","content":{"application/json":{"schema":{"type":"object","properties":{"projects":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"publishedAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"editorUrl":{"type":"string","format":"uri"}},"required":["id","slug","name","publishedAt","updatedAt","editorUrl"]}},"nextCursor":{"type":"string","description":"Pass as cursor to fetch the next page."}},"required":["projects"]}}}}}}},"/projects/templates":{"get":{"operationId":"listTemplates","summary":"List team templates","description":"List your team's templates. Use a returned id as the templateId when generating a project. Only team templates are supported.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"number","minimum":1,"maximum":100,"default":50,"description":"Max results per page."},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","description":"Pagination cursor from a previous response."},"required":false,"name":"cursor","in":"query"}],"responses":{"200":{"description":"Template list","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Pass as templateId when generating a project."},"name":{"type":"string"},"screenshotUrl":{"type":["string","null"]},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","screenshotUrl","updatedAt"]}},"nextCursor":{"type":"string","description":"Pass as cursor to fetch the next page."}},"required":["templates"]}}}}}}},"/projects/{slug}":{"get":{"operationId":"getProject","summary":"Get project details","description":"Fetch a project's metadata, latest version, and published URL.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"publishedAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"editorUrl":{"type":"string","format":"uri"},"createdAt":{"type":"string","format":"date-time"},"publishedUrl":{"type":["string","null"],"format":"uri"},"latestVersion":{"type":["object","null"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","createdAt"]}},"required":["id","slug","name","publishedAt","updatedAt","editorUrl","createdAt","publishedUrl","latestVersion"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"renameProject","summary":"Rename a project","description":"Update a project's display name. The slug and URLs are unchanged.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":191,"description":"The new display name."}},"required":["name"]}}}},"responses":{"200":{"description":"Project renamed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"name":{"type":"string"}},"required":["success","name"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/config":{"get":{"operationId":"getProjectConfig","summary":"Get project configuration","description":"Read project.config.json, including layout settings and the shared design system tokens used across slides.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Project configuration","content":{"application/json":{"schema":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/ProjectConfig"}},"required":["config"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"updateProjectConfig","summary":"Update project configuration","description":"Update project.config.json. Only keys present in config are changed; other keys are preserved. Use this to define or update the project design system under tokens before styling slides. See getSlideGuide for token naming rules.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"config":{"allOf":[{"$ref":"#/components/schemas/ProjectConfig"},{"description":"Partial project config to merge into the existing file."}]}},"required":["config"]}}}},"responses":{"200":{"description":"Project configuration updated","content":{"application/json":{"schema":{"type":"object","properties":{"versionId":{"type":"string","description":"The new project version ID."},"config":{"$ref":"#/components/schemas/ProjectConfig"}},"required":["versionId","config"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/duplicate":{"post":{"operationId":"duplicateProject","summary":"Duplicate a project","description":"Create a full copy of a project, including all slides. The copy gets its own slug and a fresh unpublished URL.","tags":["Projects"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Project duplicated","content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string"},"projectSlug":{"type":"string"},"name":{"type":"string"},"editorUrl":{"type":"string","format":"uri"}},"required":["projectId","projectSlug","name","editorUrl"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/publish":{"post":{"operationId":"publishProject","summary":"Publish a project","description":"Publish the project's latest version, making it publicly accessible at its live URL.","tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Project published","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"published":{"type":"boolean"},"publishedUrl":{"type":["string","null"],"format":"uri"}},"required":["success","published","publishedUrl"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"unpublishProject","summary":"Unpublish a project","description":"Take a published project offline. The project and its slides are kept and can be re-published later.","tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Project unpublished","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"published":{"type":"boolean"}},"required":["success","published"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/url":{"get":{"operationId":"getProjectUrl","summary":"Get the project URL config","description":"Get the project's current live URL (subdomain or custom domain plus path) and the subdomains/domains available to switch to.","tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"URL configuration","content":{"application/json":{"schema":{"type":"object","properties":{"current":{"type":"object","properties":{"type":{"type":"string","enum":["subdomain","domain"]},"hostname":{"type":"string"},"path":{"type":"string"},"subdomainId":{"type":"string"},"domainId":{"type":"string"},"projectSubdomainId":{"type":"string"},"projectDomainId":{"type":"string"}},"required":["type","hostname","path"]},"availableSubdomains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"subdomain":{"type":"string"},"isCustom":{"type":"boolean"}},"required":["id","subdomain","isCustom"]}},"availableDomains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"}},"required":["id","hostname"]}}},"required":["current","availableSubdomains","availableDomains"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"updateProjectUrl","summary":"Update the project URL","description":"Change the path, switch subdomains, or point the project at a custom domain. Provide exactly one of userSubdomainId or userDomainId. Requires a paid plan.","tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"path":{"type":"string","description":"The path segment after the hostname."},"userSubdomainId":{"type":"string","description":"ID of the subdomain to host on."},"userDomainId":{"type":"string","description":"ID of the custom domain to host on."}},"required":["path"]}}}},"responses":{"200":{"description":"URL updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"current":{"type":"object","properties":{"type":{"type":"string","enum":["subdomain","domain"]},"hostname":{"type":"string"},"path":{"type":"string"},"subdomainId":{"type":"string"},"domainId":{"type":"string"},"projectSubdomainId":{"type":"string"},"projectDomainId":{"type":"string"}},"required":["type","hostname","path"]}},"required":["success","current"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Paid plan required","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"URL already in use","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/subdomains":{"post":{"operationId":"createCustomSubdomain","summary":"Create a custom subdomain","description":"Create a custom subdomain for the project's team. Connect it with updateProjectUrl. Requires a paid plan.","tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"subdomain":{"type":"string","description":"The subdomain label (lowercase letters, numbers, hyphens)."}},"required":["subdomain"]}}}},"responses":{"200":{"description":"Subdomain created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"subdomain":{"type":"object","properties":{"id":{"type":"string"},"subdomain":{"type":"string"}},"required":["id","subdomain"]}},"required":["success","subdomain"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Paid plan required or subdomain limit reached","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Subdomain already taken","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/domains":{"post":{"operationId":"createCustomDomain","summary":"Connect a custom domain","description":"Register a custom domain for the project's team and return the DNS records to configure. Point the project at it with updateProjectUrl once DNS is set up. Requires a paid plan.","tags":["Publishing"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"hostname":{"type":"string","description":"The domain to connect, without protocol or 'www'."}},"required":["hostname"]}}}},"responses":{"200":{"description":"Domain connected","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"domain":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"}},"required":["id","hostname"]},"dns":{"type":["object","null"],"properties":{"verified":{"type":"boolean"},"misconfigured":{"type":"boolean"},"certPending":{"type":"boolean"},"recommendedRecords":{"type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["verified","misconfigured","certPending","recommendedRecords"]},"next":{"type":"string"}},"required":["success","domain","dns","next"]}}}},"400":{"description":"Invalid domain format","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Paid plan required","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Domain already taken","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/slides":{"get":{"operationId":"listSlides","summary":"List slides","description":"List all slides in a project. Returns slide IDs and names.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Slide list","content":{"application/json":{"schema":{"type":"object","properties":{"slides":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The slide (face) ID."},"name":{"type":"string","description":"The slide display name."}},"required":["id","name"]}}},"required":["slides"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createSlides","summary":"Create one or more slides","description":"Create one or more empty slides in order in a single atomic call. Returns the new slideIds in the order they were created. Always batch every slide you want to add into one call instead of calling this endpoint multiple times concurrently. After creation, call updateSlide on each returned slideId to write real content.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slides":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Display name for the new slide.","example":"Hero Section"}},"required":["name"]},"minItems":1,"description":"Ordered list of slides to create. The first entry is inserted immediately after afterSlideId (or at the end if omitted); each subsequent entry is inserted after the previous one."},"afterSlideId":{"type":"string","description":"Insert the new slides immediately after this slide ID. Omit to append at the end."},"editing":{"type":"boolean","description":"If true, immediately shows the loading gradient on every new slide. Call finishSlideEditing on each when done."}},"required":["slides"]}}}},"responses":{"200":{"description":"Slides created","content":{"application/json":{"schema":{"type":"object","properties":{"slides":{"type":"array","items":{"type":"object","properties":{"slideId":{"type":"string","description":"The new slide ID."},"name":{"type":"string"}},"required":["slideId","name"]},"description":"The newly created slides, in the same order they were requested."},"versionId":{"type":"string","description":"The new project version ID."}},"required":["slides","versionId"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"operationId":"reorderSlides","summary":"Reorder all slides","description":"Reorder every slide in a project in a single atomic call. The request body's slideIds array must contain exactly the project's existing slide IDs (no duplicates, no missing, no extras), in the desired final order. Both the persisted project state and the live editor view end up in the same order.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"slideIds":{"type":"array","items":{"type":"string"},"minItems":1,"description":"Full ordered list of every existing slide ID, in the desired final order. Must equal the set of IDs currently in the project."}},"required":["slideIds"]}}}},"responses":{"200":{"description":"Slides reordered","content":{"application/json":{"schema":{"type":"object","properties":{"slideIds":{"type":"array","items":{"type":"string"},"description":"The new order of slide IDs in the project."},"versionId":{"type":"string","description":"The new project version ID."}},"required":["slideIds","versionId"]}}}},"400":{"description":"Validation error","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/slides/{slideId}":{"get":{"operationId":"getSlide","summary":"Get slide source files","description":"Read a slide's source code and configuration. Returns face.tsx, face.content.json, and face.controls.json.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string","description":"The slide ID from listSlides."},"required":true,"name":"slideId","in":"path"}],"responses":{"200":{"description":"Slide files","content":{"application/json":{"schema":{"type":"object","properties":{"slideId":{"type":"string"},"name":{"type":"string"},"files":{"type":"object","properties":{"face.tsx":{"type":"string","description":"React component. Must default-export a component with w-full h-full outer div. MUST import content/controls from sibling JSON files. Can import any npm package (auto-resolved). Use Tailwind CSS and container queries for desktop sizing per the slide authoring guide. Base/mobile typography must fit the 9:16 canvas; use moderate mobile headings and scale up behind the project's desktop container breakpoint for presentation sizes. Google Fonts via: import { Inter } from 'next/font/google'. Custom CSS via: import './face.css'."},"face.content.json":{"type":"string","description":"Editable content blocks. ALL visible text must go here — never hardcode text in face.tsx. Structure: { \"blocks\": { \"key\": { \"type\": \"text\"|\"image\"|\"icon\"|\"table\", ... } } }. Text: { \"type\": \"text\", \"content\": \"HTML\" } rendered with <TextContent>. Image: { \"type\": \"image\", \"src\": \"url\" }. Icon: { \"type\": \"icon\", \"name\": \"lucide-icon-name\" } rendered with <Icon>. Table: { \"type\": \"table\", \"columns\": [...], \"rows\": [...] }."},"face.controls.json":{"type":"string","description":"Editor controls. Always add controls for sizes, spacing, visibility, layout. Structure: { \"controls\": { \"key\": { \"type\": \"slider\"|\"switch\"|\"selector\", ... } } }. Slider: { \"type\": \"slider\", \"min\": 0, \"max\": 100, \"step\": 1, \"value\": 50 }. Switch: { \"type\": \"switch\", \"value\": true }. Selector: { \"type\": \"selector\", \"options\": [\"A\", \"B\"], \"value\": \"A\" }. Access: controls.key?.value ?? default."}},"description":"Slide source files. Only include files you want to update."}},"required":["slideId","name","files"]}}}},"404":{"description":"Project or slide not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"operationId":"updateSlide","summary":"Update slide files","description":"Update a slide's source files. Only provided files are changed. The code is compiled and validated before saving — returns 400 with detailed errors if it doesn't compile. Workflow: start_slide_editing → get_slide → updateSlide → finish_slide_editing.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"slideId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"files":{"type":"object","properties":{"face.tsx":{"type":"string","description":"React component. Must default-export a component with w-full h-full outer div. MUST import content/controls from sibling JSON files. Can import any npm package (auto-resolved). Use Tailwind CSS and container queries for desktop sizing per the slide authoring guide. Base/mobile typography must fit the 9:16 canvas; use moderate mobile headings and scale up behind the project's desktop container breakpoint for presentation sizes. Google Fonts via: import { Inter } from 'next/font/google'. Custom CSS via: import './face.css'."},"face.content.json":{"type":"string","description":"Editable content blocks. ALL visible text must go here — never hardcode text in face.tsx. Structure: { \"blocks\": { \"key\": { \"type\": \"text\"|\"image\"|\"icon\"|\"table\", ... } } }. Text: { \"type\": \"text\", \"content\": \"HTML\" } rendered with <TextContent>. Image: { \"type\": \"image\", \"src\": \"url\" }. Icon: { \"type\": \"icon\", \"name\": \"lucide-icon-name\" } rendered with <Icon>. Table: { \"type\": \"table\", \"columns\": [...], \"rows\": [...] }."},"face.controls.json":{"type":"string","description":"Editor controls. Always add controls for sizes, spacing, visibility, layout. Structure: { \"controls\": { \"key\": { \"type\": \"slider\"|\"switch\"|\"selector\", ... } } }. Slider: { \"type\": \"slider\", \"min\": 0, \"max\": 100, \"step\": 1, \"value\": 50 }. Switch: { \"type\": \"switch\", \"value\": true }. Selector: { \"type\": \"selector\", \"options\": [\"A\", \"B\"], \"value\": \"A\" }. Access: controls.key?.value ?? default."}},"description":"Slide source files. Only include files you want to update."}},"required":["files"]}}}},"responses":{"200":{"description":"Slide updated","content":{"application/json":{"schema":{"type":"object","properties":{"slideId":{"type":"string"},"versionId":{"type":"string","description":"The new project version ID."},"files":{"type":"object","properties":{"face.tsx":{"type":"string","description":"React component. Must default-export a component with w-full h-full outer div. MUST import content/controls from sibling JSON files. Can import any npm package (auto-resolved). Use Tailwind CSS and container queries for desktop sizing per the slide authoring guide. Base/mobile typography must fit the 9:16 canvas; use moderate mobile headings and scale up behind the project's desktop container breakpoint for presentation sizes. Google Fonts via: import { Inter } from 'next/font/google'. Custom CSS via: import './face.css'."},"face.content.json":{"type":"string","description":"Editable content blocks. ALL visible text must go here — never hardcode text in face.tsx. Structure: { \"blocks\": { \"key\": { \"type\": \"text\"|\"image\"|\"icon\"|\"table\", ... } } }. Text: { \"type\": \"text\", \"content\": \"HTML\" } rendered with <TextContent>. Image: { \"type\": \"image\", \"src\": \"url\" }. Icon: { \"type\": \"icon\", \"name\": \"lucide-icon-name\" } rendered with <Icon>. Table: { \"type\": \"table\", \"columns\": [...], \"rows\": [...] }."},"face.controls.json":{"type":"string","description":"Editor controls. Always add controls for sizes, spacing, visibility, layout. Structure: { \"controls\": { \"key\": { \"type\": \"slider\"|\"switch\"|\"selector\", ... } } }. Slider: { \"type\": \"slider\", \"min\": 0, \"max\": 100, \"step\": 1, \"value\": 50 }. Switch: { \"type\": \"switch\", \"value\": true }. Selector: { \"type\": \"selector\", \"options\": [\"A\", \"B\"], \"value\": \"A\" }. Access: controls.key?.value ?? default."}},"description":"Slide source files. Only include files you want to update."}},"required":["slideId","versionId","files"]}}}},"400":{"description":"Validation or compilation error. Returns detailed errors if the slide code doesn't compile.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"errors":{"type":"array","items":{"type":"object","properties":{"message":{"type":"string","description":"Error description."},"file":{"type":"string","description":"File path where the error occurred."},"type":{"type":"string","description":"Error type (e.g. build_error, invalid_content_schema, missing_face_files)."}},"required":["message","type"]}}},"required":["error","errors"]}}}},"404":{"description":"Project or slide not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/slides/{slideId}/editing":{"post":{"operationId":"startSlideEditing","summary":"Start slide editing","description":"Signal that an agent is about to edit a slide. Shows a loading gradient in the editor UI. Call before making changes with updateSlide. Always call finishSlideEditing when done.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"slideId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"agentName":{"type":"string","description":"Name of the agent editing (shown in UI). Defaults to \"AI Agent\"."}}}}}},"responses":{"200":{"description":"Editing session started","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"operationId":"finishSlideEditing","summary":"Finish slide editing","description":"Signal that an agent is done editing a slide. Clears the loading indicator. Always call this after editing, even if the edit failed.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"slideId","in":"path"}],"responses":{"200":{"description":"Editing indicator cleared","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"404":{"description":"Project not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/slides/guide":{"get":{"operationId":"getSlideAuthoringGuide","summary":"Get slide authoring guide","description":"Returns the slide authoring guide — conventions and best practices for writing face.tsx, face.content.json, and face.controls.json. Fetch once and include in your agent's system prompt before calling updateSlide.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"Project to tailor the guide to its mobile canvas size. Omit when authoring a new project to get the default guide."},"required":false,"name":"projectSlug","in":"query"}],"responses":{"200":{"description":"Slide authoring guide","content":{"application/json":{"schema":{"type":"object","properties":{"guide":{"type":"string","description":"The slide authoring guide as a markdown string."}},"required":["guide"]}}}}}}},"/projects/{slug}/slides/{slideId}/screenshot":{"post":{"operationId":"captureSlideScreenshot","summary":"Capture slide screenshot","description":"Take a screenshot of a slide as it currently renders. The slide is rendered headlessly in the cloud against the latest saved version of the project, and the JPEG is uploaded to a public CDN. Returns the screenshot URL. Use this to visually verify a slide after editing it. Pass isMobile=true to capture the mobile layout.","tags":["Slides"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"slideId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"isMobile":{"type":"boolean","description":"Capture the mobile layout instead of desktop. Defaults to false."}}}}}},"responses":{"200":{"description":"Screenshot captured","content":{"application/json":{"schema":{"type":"object","properties":{"slideId":{"type":"string"},"screenshotUrl":{"type":"string","format":"uri","description":"Public CDN URL of the captured JPEG."}},"required":["slideId","screenshotUrl"]}}}},"404":{"description":"Project or slide not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Screenshots are not configured on the server","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/plugins":{"get":{"operationId":"listPlugins","summary":"List available plugins","description":"List the face plugins available to attach to a slide. Plugins add runtime behaviors a slide's React code can't express on its own, such as collecting form submissions or embedding a live AI video presenter. Call getPluginDocs for a plugin's config schema and code examples before configuring it.","tags":["Plugins"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Available plugins","content":{"application/json":{"schema":{"type":"object","properties":{"plugins":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The plugin ID, e.g. 'form' or 'presenter'."},"displayName":{"type":"string"},"description":{"type":"string"}},"required":["id","displayName","description"]}}},"required":["plugins"]}}}}}}},"/plugins/{pluginId}":{"get":{"operationId":"getPluginDocs","summary":"Get plugin docs","description":"Fetch the full markdown docs for a plugin: its config schema, the functions it exposes, and code examples showing how a slide's face.tsx calls it (e.g. useFormPlugin / usePresenterPlugin). Read this before configuring the plugin.","tags":["Plugins"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","description":"The plugin ID from listPlugins."},"required":true,"name":"pluginId","in":"path"}],"responses":{"200":{"description":"Plugin docs","content":{"application/json":{"schema":{"type":"object","properties":{"pluginId":{"type":"string"},"docs":{"type":"string","description":"The plugin docs as a markdown string."}},"required":["pluginId","docs"]}}}},"404":{"description":"Unknown plugin","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/projects/{slug}/slides/{slideId}/plugins":{"post":{"operationId":"setupPlugin","summary":"Configure a plugin on a slide","description":"Configure a plugin instance on a slide. The config is validated against the plugin's schema and written to the slide's face.plugins.json. Other plugin instances on the slide are preserved. By default this refuses to overwrite an existing instance with the same localName (returns 409) — pass overwrite: true to replace its config, or use a fresh localName to add another instance. After setup, wire the plugin into the slide's face.tsx via its hook (see getPluginDocs).","tags":["Plugins"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"slug","in":"path"},{"schema":{"type":"string"},"required":true,"name":"slideId","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pluginId":{"type":"string","description":"The plugin ID from listPlugins."},"localName":{"type":"string","description":"Identifier for this instance, referenced in code as useFormPlugin/usePresenterPlugin(localName). camelCase or snake_case, starting with a letter."},"config":{"type":"object","additionalProperties":{},"description":"Config object matching the plugin's config schema (see getPluginDocs)."},"overwrite":{"type":"boolean","description":"Set true to replace an existing instance with the same localName. Defaults to false."}},"required":["pluginId","localName","config"]}}}},"responses":{"200":{"description":"Plugin configured","content":{"application/json":{"schema":{"type":"object","properties":{"slideId":{"type":"string"},"versionId":{"type":"string","description":"The new project version ID."},"instanceId":{"type":"string","description":"The configured instance id, formatted as `${slideId}.${localName}`."},"pluginId":{"type":"string"},"created":{"type":"boolean","description":"True if a new instance was created, false if an existing one was overwritten."},"warning":{"type":"string","description":"Present when the config was saved but a post-save side effect (e.g. presenter avatar provisioning) failed. The instance is configured; address the warning and call setupPlugin again with overwrite: true to retry."}},"required":["slideId","versionId","instanceId","pluginId","created"]}}}},"400":{"description":"Invalid config, or the slide's existing face.plugins.json is corrupt","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Project or slide not found","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"An instance with this localName already exists and overwrite was not set","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/teams":{"get":{"operationId":"listTeams","summary":"List teams","description":"List the teams the authenticated user belongs to. The personal team is flagged with isPersonal: true and is the default team for new projects when no team context is supplied.","tags":["Teams"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Team list","content":{"application/json":{"schema":{"type":"object","properties":{"teams":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The team ID."},"slug":{"type":"string","description":"The team slug (subdomain)."},"name":{"type":"string"},"isPersonal":{"type":"boolean","description":"True for the user's auto-created personal team."},"role":{"type":"string","enum":["OWNER","MEMBER"],"description":"The authenticated user's role in this team."}},"required":["id","slug","name","isPersonal","role"]}}},"required":["teams"]}}}},"401":{"description":"Authentication required","headers":{"X-Faces-Error-Code":{"description":"Stable machine-readable error code for grouping and handling failures.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/auth/create-key":{"post":{"operationId":"createApiKey","summary":"Create an API key","description":"Create a new API key scoped to a team. The key inherits the team's access — projects created with it are owned by that team. The raw key is returned once, so store it securely. Omit both teamId and team to use your personal team.","tags":["Auth"],"security":[{"bearerAuth":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"default":"Default","description":"A label for the key."},"team":{"type":"string","description":"Team id or slug to scope the key to. The authenticated user must be a member. Defaults to your personal team."}}}}}},"responses":{"200":{"description":"API key created","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"The raw API key. Shown once."},"keyPrefix":{"type":"string","description":"First 10 characters for identification."},"name":{"type":"string"}},"required":["key","keyPrefix","name"]}}}}}}}},"webhooks":{}}