{"openapi":"3.1.0","info":{"title":"Goodeye API","version":"0.1.0"},"paths":{"/admin/analytics":{"get":{"summary":"Admin Analytics","description":"Aggregate product analytics for platform admins.\n\n``exclude_internal`` (default ``true``) hides internal company users from\nevery metric so the dashboard reflects external usage; pass\n``exclude_internal=false`` to count internal users alongside external ones.","operationId":"admin_analytics_admin_analytics_get","parameters":[{"name":"period","in":"query","required":false,"schema":{"type":"string","default":"30d","title":"Period"}},{"name":"exclude_internal","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Exclude Internal"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Admin Analytics Admin Analytics Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/register":{"post":{"summary":"Register","operationId":"register_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthStartIn"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Register Register Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/login":{"post":{"summary":"Login","operationId":"login_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthStartIn"}}},"required":true},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Login Login Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/register/verify":{"post":{"summary":"Register Verify","operationId":"register_verify_register_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Register Verify Register Verify Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/login/verify":{"post":{"summary":"Login Verify","operationId":"login_verify_login_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Login Verify Login Verify Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/exchange":{"post":{"summary":"Exchange","description":"Rotate the caller's host-scoped CLI key and return the new plaintext.\n\nRevokes every live key named ``cli-{hostname}`` or\n``cli-{hostname}-{suffix}`` for this user, then mints a fresh one.","operationId":"exchange_auth_exchange_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExchangeIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Exchange Auth Exchange Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/me":{"get":{"summary":"Me","description":"Look up your own account profile: id, email, and handle.\n\nResponse shape: ``{id, email, handle, handle_claimed_at}``.\n``id`` is the stable account identifier for this user (a UUID string).","operationId":"me_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Me Me Get"}}}}}},"patch":{"summary":"Patch Me","description":"Claim a handle for the authenticated caller.\n\nReturns ``{handle, claimed_at}`` on success. Structured errors:\n``handle_invalid``, ``handle_reserved``, ``handle_taken``,\n``handle_already_claimed``.","operationId":"patch_me_me_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_MePatchIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Patch Me Me Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/me/rename-handle":{"post":{"summary":"Rename Handle Route","description":"Rename the caller's claimed handle.\n\nStructured errors: ``handle_invalid``, ``handle_reserved``,\n``handle_taken``, ``handle_not_claimed``, ``handle_rename_too_soon``\n(429), ``handle_rename_limit_exceeded`` (429).","operationId":"rename_handle_route_me_rename_handle_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_MePatchIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Rename Handle Route Me Rename Handle Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api-keys":{"post":{"summary":"Create Key","description":"Mint a new live API key for the caller.","operationId":"create_key_api_keys_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Key Api Keys Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Api Keys Route","description":"List live API keys, sliced to ``limit`` with an optional cursor.","operationId":"list_api_keys_route_api_keys_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Api Keys Route Api Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api-keys/{key_id}":{"delete":{"summary":"Delete Key","description":"Revoke a key owned by the caller. Second DELETE returns 404.\n\nThe pre-check queries for a live (non-revoked) row scoped to the\ncaller's user_id; if none exists, ``NotFound`` is raised. Otherwise\nthe shared service is invoked to stamp ``revoked_at``.","operationId":"delete_key_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/audit/skill-prompt":{"get":{"summary":"Skill Prompt","description":"Review a local skill file (one not yet saved to Goodeye) against best practices\nand surface what to fix.","operationId":"skill_prompt_audit_skill_prompt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Skill Prompt Audit Skill Prompt Get"}}}}}}},"/design/skill-prompt":{"get":{"summary":"Skill Prompt","description":"Create a new skill from scratch: start a guided session that designs the\nskill and its verifiers.","operationId":"skill_prompt_design_skill_prompt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Skill Prompt Design Skill Prompt Get"}}}}}}},"/skills":{"get":{"summary":"List Skills Route","operationId":"list_skills_route_skills_get","parameters":[{"name":"filter","in":"query","required":false,"schema":{"enum":["mine","all","shared-with-me"],"type":"string","default":"all","title":"Filter"}},{"name":"tag","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Archived"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Skills Route Skills Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Create Skill Route","operationId":"create_skill_route_skills_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveWorkflowInput"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Skill Route Skills Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/search":{"post":{"summary":"Search Skills Route","operationId":"search_skills_route_skills_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchWorkflowsInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Search Skills Route Skills Search Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/files":{"get":{"summary":"Get Skill File Route","description":"Fetch one or more files from a skill version's file tree.\n\nProvide ``path`` for a single file or ``paths`` (repeatable) for a batch.\nAt least one of the two parameters is required; supplying neither returns\na validation error. Returns content inline for text files and small binary\nfiles; binary files over the size limit return metadata with an error field\ninstead of inline bytes. Batch responses carry an additional\n``batch_response_cap_exceeded`` error when the aggregate inline budget is\nexhausted.\n\nPass ``format=raw`` with a single ``path`` to receive the file's raw bytes\ninstead of the JSON envelope. Raw serving applies no inline size ceiling, so\nit is the path the CLI's ``sync pull`` uses to mirror a binary too large to\ninline (a demo image or asset) down to disk. Pair ``format=raw`` with\n``sha256`` to content-address the fetch. Every raw response carries the same\nhardening headers as the template raw route, so a file can never execute as\nan active document in a browser. ``format`` is ignored for a batch\n(``paths``) request; raw is single-file only.","operationId":"get_skill_file_route_skills__id_or_slug__files_get","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}},{"name":"path","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Relative path of the file within the skill's file tree","title":"Path"},"description":"Relative path of the file within the skill's file tree"},{"name":"paths","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"description":"One or more relative paths for a batch fetch. Repeat the parameter for each path: ?paths=a.txt&paths=b.txt. Mutually exclusive with path.","title":"Paths"},"description":"One or more relative paths for a batch fetch. Repeat the parameter for each path: ?paths=a.txt&paths=b.txt. Mutually exclusive with path."},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}},{"name":"format","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set to 'raw' to return a single file's raw bytes instead of the JSON envelope. Unlike the inline JSON response, raw serving has no binary size ceiling, so it is the only way to retrieve a binary larger than the inline limit. Requires 'path' (not 'paths'); omit for the default structured JSON response.","title":"Format"},"description":"Set to 'raw' to return a single file's raw bytes instead of the JSON envelope. Unlike the inline JSON response, raw serving has no binary size ceiling, so it is the only way to retrieve a binary larger than the inline limit. Requires 'path' (not 'paths'); omit for the default structured JSON response."},{"name":"sha256","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Content address of the expected file. When provided with format=raw, the file is resolved by path and then confirmed to match this value; a stale or mismatched address returns not found.","title":"Sha256"},"description":"Content address of the expected file. When provided with format=raw, the file is resolved by path and then confirmed to match this value; a stale or mismatched address returns not found."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Update Skill Files Route","description":"Change specific files in a skill, keeping every path the request does not name.\n\nOnly the paths in ``files`` and ``delete_paths`` are touched: everything\nelse rides forward unchanged, so a caller editing one file never has to\nread back and resend the rest of the tree. This is the opposite of\n``POST /v1/skills``, where ``files`` is a full snapshot and any path left\nout is deleted.\n\nEach entry in ``files`` carries that file's complete new content, and the\nreserved path ``SKILL.md`` rewrites the runbook itself. ``executable`` and\n``purpose`` keep their current values unless set. Requires edit access and\na current ``expected_version_token``; writes the next version of the skill.","operationId":"update_skill_files_route_skills__id_or_slug__files_patch","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_UpdateSkillFilesIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Update Skill Files Route Skills  Id Or Slug  Files Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}":{"get":{"summary":"Get Skill Route","operationId":"get_skill_route_skills__id_or_slug__get","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}},{"name":"accept","in":"header","required":false,"schema":{"type":"string","default":"application/json","title":"Accept"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Skill Route","description":"Permanently and immediately erase a skill you own.\n\nThis is permanent: the skill, all its versions, all attached files, and\nall access grants are removed from the live system at once. There is no\nrecovery path. Use ``POST /{id_or_slug}/archive`` if you want a reversible\nalternative.\n\nEncrypted backups age out within the platform's standard retention window\n(up to three months), so the data is not instantly erased from all systems\neverywhere, but it is no longer accessible through any product surface after\nthis call.\n\nOwner only. Works on both live and archived skills.\n\nReturns ``{skill_id, name, deleted: true}``.","operationId":"delete_skill_route_skills__id_or_slug__delete","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Skill Route Skills  Id Or Slug  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/versions/{version}":{"get":{"summary":"Get Skill Version Route","operationId":"get_skill_version_route_skills__id_or_slug__versions__version__get","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}},{"name":"version","in":"path","required":true,"schema":{"type":"integer","title":"Version"}},{"name":"accept","in":"header","required":false,"schema":{"type":"string","default":"application/json","title":"Accept"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Skill Version Route","description":"Permanently and immediately erase a single non-current skill version.\n\nThis is permanent: the version row, all its attached files, and any\ncontent that is no longer referenced by any surviving version or published\ntemplate version are removed from the live system at once. There is no\nrecovery path. Use ``POST /{id_or_slug}/archive`` if you want a reversible\nalternative for the whole skill.\n\nEncrypted backups age out within the platform's standard retention window\n(up to three months), so the data is not instantly erased from all systems\neverywhere, but it is no longer accessible through any product surface after\nthis call.\n\nThe current (live) version cannot be erased with this call. Use\n``DELETE /{id_or_slug}`` to permanently remove the entire skill including\nits current version.\n\nVersion numbers remain monotonic with a gap where the erased version was.\nSurviving versions are not renumbered.\n\nOwner only. Returns ``{skill_id, version, deleted: true}``.","operationId":"delete_skill_version_route_skills__id_or_slug__versions__version__delete","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}},{"name":"version","in":"path","required":true,"schema":{"type":"integer","title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Skill Version Route Skills  Id Or Slug  Versions  Version  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/lineage":{"get":{"summary":"Get Skill Lineage Route","operationId":"get_skill_lineage_route_skills__id_or_slug__lineage_get","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Skill Lineage Route Skills  Id Or Slug  Lineage Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/teach":{"post":{"summary":"Teach Skill Route","description":"Improve an existing skill by hand: teach it from examples and corrections you provide.","operationId":"teach_skill_route_skills__id_or_slug__teach_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Teach Skill Route Skills  Id Or Slug  Teach Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/optimize":{"post":{"summary":"Optimize Skill Route","description":"Automatically improve an existing skill: runs an optimization loop to lift it\nagainst its outcome.","operationId":"optimize_skill_route_skills__id_or_slug__optimize_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}},{"name":"max_iterations","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Max Iterations"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Optimize Skill Route Skills  Id Or Slug  Optimize Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/optimize-description":{"post":{"summary":"Optimize Description Route","description":"Tune a skill's trigger: sharpen its description so it fires at the right times.","operationId":"optimize_description_route_skills__id_or_slug__optimize_description_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}},{"name":"max_iterations","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"title":"Max Iterations"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Optimize Description Route Skills  Id Or Slug  Optimize Description Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/audit":{"post":{"summary":"Audit Skill Route","description":"Review an existing skill against best practices and fix what it flags.","operationId":"audit_skill_route_skills__id_or_slug__audit_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Audit Skill Route Skills  Id Or Slug  Audit Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/archive":{"post":{"summary":"Archive Skill Route","description":"Archive a skill you own. Sets archived_at and keeps the slug occupied.","operationId":"archive_skill_route_skills__id_or_slug__archive_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Archive Skill Route Skills  Id Or Slug  Archive Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/unarchive":{"post":{"summary":"Unarchive Skill Route","description":"Restore an archived skill. Clears archived_at and re-derives grants.","operationId":"unarchive_skill_route_skills__id_or_slug__unarchive_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Unarchive Skill Route Skills  Id Or Slug  Unarchive Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/grants":{"post":{"summary":"Grant Skill Route","operationId":"grant_skill_route_skills__id_or_slug__grants_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_GrantSkillIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Grant Skill Route Skills  Id Or Slug  Grants Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Skill Grants Route","operationId":"list_skill_grants_route_skills__id_or_slug__grants_get","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Skill Grants Route Skills  Id Or Slug  Grants Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Revoke Skill Grant Route","operationId":"revoke_skill_grant_route_skills__id_or_slug__grants_delete","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_RevokeSkillGrantIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revoke Skill Grant Route Skills  Id Or Slug  Grants Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/leave":{"post":{"summary":"Leave Shared Skill Route","operationId":"leave_shared_skill_route_skills__id_or_slug__leave_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Leave Shared Skill Route Skills  Id Or Slug  Leave Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/safety-check":{"post":{"summary":"Check Skill Safety Route","description":"Check a skill for embedded secrets or private data before you publish it as a template.","operationId":"check_skill_safety_route_skills__id_or_slug__safety_check_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Check Skill Safety Route Skills  Id Or Slug  Safety Check Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/skills/{id_or_slug}/transfer-ownership":{"post":{"summary":"Transfer Skill Ownership Route","operationId":"transfer_skill_ownership_route_skills__id_or_slug__transfer_ownership_post","parameters":[{"name":"id_or_slug","in":"path","required":true,"schema":{"type":"string","title":"Id Or Slug"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_TransferSkillOwnershipIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Transfer Skill Ownership Route Skills  Id Or Slug  Transfer Ownership Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates":{"get":{"summary":"List Templates Route","description":"Browse the public template catalog.","operationId":"list_templates_route_templates_get","parameters":[{"name":"filter","in":"query","required":false,"schema":{"enum":["mine","all"],"type":"string","default":"all","title":"Filter"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"include_archived","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Include Archived"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Templates Route Templates Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Publish Template Version Route","description":"Publish a skill as a new template version.\n\nBundle a ``demo/README.md`` writeup with images referenced by relative path\ninside ``demo/`` to render a visual demo on the public template page.\n\nPublishing makes the template's verifier definitions public: anyone who\nviews the template (including anonymous readers) can read each verifier's\ncriterion and calibration examples. Publishing is hard-blocked\n(``SafetyVerificationFailed``) if a verifier definition contains a secret or\ncredential, and flagged if it appears to contain private data. When the\ntemplate references verifiers, the response includes a\n``verifier_exposure_notice`` restating this.\n\n``SafetyVerificationFailed`` (422) and ``SafetyVerificationRuntimeError``\n(503) propagate to the app-level ``GoodeyeError`` handler which\nserializes them via ``to_wire``.","operationId":"publish_template_version_route_templates_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishTemplateVersionInput"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Publish Template Version Route Templates Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/search":{"post":{"summary":"Search Templates Route","description":"Search the public template catalog by natural-language query.","operationId":"search_templates_route_templates_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchTemplatesInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Search Templates Route Templates Search Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/fork":{"post":{"summary":"Fork Template Route","description":"Copy a public template into your own private skill.","operationId":"fork_template_route_templates_fork_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForkTemplateInput"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Fork Template Route Templates Fork Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/versions/{version}":{"delete":{"summary":"Unpublish Template Version Route","description":"Unpublish a template version to stop showing it to readers (distinct from\ndeprecate and permanent delete).","operationId":"unpublish_template_version_route_templates__template_identifier__versions__version__delete","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}},{"name":"version","in":"path","required":true,"schema":{"type":"integer","title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Unpublish Template Version Route Templates  Template Identifier  Versions  Version  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/versions/{version}/permanent":{"delete":{"summary":"Delete Template Version Route","description":"Permanently and immediately erase a single template version.\n\nThis is permanent: the version row, all its attached files, all version\nverification records, and any content no longer referenced by any\nsurviving version or skill version are removed from the live system at\nonce. There is no recovery path. Use ``POST .../archive`` if you want a\nreversible alternative for the whole template.\n\nEncrypted backups age out within the platform's standard retention window\n(up to three months), so the data is not instantly erased from all systems\neverywhere, but it is no longer accessible through any product surface\nafter this call.\n\nServing gate: the version must be unpublished first\n(``DELETE .../versions/{version}``). A still-published version cannot be\npermanently deleted because it is currently served to readers. Use\n``DELETE /v1/templates/{template_ref}`` to remove the entire template at\nonce.\n\nVersion numbers remain monotonic with a gap where the erased version was.\nSurviving versions are not renumbered.\n\nReturns 200 with ``{template_id, version, deleted: true}``.","operationId":"delete_template_version_route_templates__template_identifier__versions__version__permanent_delete","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}},{"name":"version","in":"path","required":true,"schema":{"type":"integer","title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Template Version Route Templates  Template Identifier  Versions  Version  Permanent Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/versions/{version}/deprecate":{"post":{"summary":"Deprecate Template Version Route","description":"Mark a template version as deprecated without hiding it.\n\nDistinct from ``DELETE /v1/templates/{template_identifier}/versions/{version}``\n(unpublish): deprecate is a soft signal, unpublish is the hide path.","operationId":"deprecate_template_version_route_templates__template_identifier__versions__version__deprecate_post","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}},{"name":"version","in":"path","required":true,"schema":{"type":"integer","title":"Version"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeprecateTemplateVersionInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Deprecate Template Version Route Templates  Template Identifier  Versions  Version  Deprecate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/safety-check":{"post":{"summary":"Check Template Safety Route","description":"Check a published template version for embedded secrets or private data.\n\nAuth is optional: anonymous callers bill against the per-IP-hash\nanonymous grant via the metering chokepoint.\n\nFields longer than the safety check's input limit are truncated for this\nscan and flagged in the response (``truncated`` plus ``truncated_fields``);\ngenuinely invalid input returns 400 ``validation_error``.","operationId":"check_template_safety_route_templates__template_identifier__safety_check_post","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Check Template Safety Route Templates  Template Identifier  Safety Check Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/transfer-ownership":{"post":{"summary":"Transfer Template Ownership Route","description":"Transfer template ownership to another Goodeye user. Owner only.","operationId":"transfer_template_ownership_route_templates__template_identifier__transfer_ownership_post","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TransferTemplateOwnershipInput"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Transfer Template Ownership Route Templates  Template Identifier  Transfer Ownership Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/archive":{"post":{"summary":"Archive Template Route","description":"Archive a template owned by the caller.\n\nBody is optional (``{archive_reason}``). Archiving keeps the slug\noccupied and hides the template from public listing. Forks pinned at\nthis template keep working.","operationId":"archive_template_route_templates__template_identifier__archive_post","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ArchiveTemplateInput"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Archive Template Route Templates  Template Identifier  Archive Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/unarchive":{"post":{"summary":"Unarchive Template Route","description":"Restore an archived template. Owner only. Idempotent on live templates.","operationId":"unarchive_template_route_templates__template_identifier__unarchive_post","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Unarchive Template Route Templates  Template Identifier  Unarchive Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}/files":{"get":{"summary":"Get Template File Route","description":"Fetch a single file from a template version's file tree.\n\n``path`` must match a row in the template's file manifest (use\n``get_template`` to see the manifest). ``SKILL.md`` returns the template\nbody. Text files return the decoded string in ``content``. Small binary\nfiles return base64-encoded bytes in ``content_base64``. Binary files over\nthe size limit return metadata and an ``error`` field with no inline bytes.\n\nPass ``format=raw`` to receive the file's raw bytes instead of the JSON\nenvelope. This is the path public template pages use to render demo images:\na validated image is served with its pinned image type, anything else is\nserved as a generic download attachment, and every raw response carries\nhardening headers so a file can never execute as an active document in a\nbrowser. Pair ``format=raw`` with ``sha256`` so the URL is content\naddressed: a republished or removed file no longer resolves at a stale\naddress. The default (no ``format``) JSON response is unchanged.\n\nAnonymous callers may fetch files from live (published) template versions.\nOnce a version is unpublished, anonymous reads are denied immediately; the\nliveness check is evaluated per read inside the same transaction, including\nfor ``format=raw``.\n\nWhen ``path`` is omitted this is not a file request: the greedy ``:path``\nsegment swallowed a template whose slug is literally ``files`` (an\n``@handle/files`` URL), so fall through to ordinary template resolution on\nthe reconstructed identifier. Publishing a new template with that slug is\nrejected up front, but legacy templates created before this route existed\nmust still resolve here. (Per-file fetches against such a legacy template\ncannot be disambiguated from this route and are not supported, but those\nrows predate sibling files so their only file is the synthesized SKILL.md,\nwhich the no-path body resolution already returns.)","operationId":"get_template_file_route_templates__template_identifier__files_get","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}},{"name":"path","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Relative path of the file within the template's file tree","title":"Path"},"description":"Relative path of the file within the template's file tree"},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}},{"name":"format","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set to 'raw' to return the file's raw bytes (used to render images on public template pages). Omit for the default structured JSON response.","title":"Format"},"description":"Set to 'raw' to return the file's raw bytes (used to render images on public template pages). Omit for the default structured JSON response."},{"name":"sha256","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Content address of the expected file. When provided, the file is resolved by path and then confirmed to match this value; a stale or mismatched address returns not found.","title":"Sha256"},"description":"Content address of the expected file. When provided, the file is resolved by path and then confirmed to match this value; a stale or mismatched address returns not found."},{"name":"accept","in":"header","required":false,"schema":{"type":"string","default":"application/json","title":"Accept"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"summary":"Get Template File Route","description":"Fetch a single file from a template version's file tree.\n\n``path`` must match a row in the template's file manifest (use\n``get_template`` to see the manifest). ``SKILL.md`` returns the template\nbody. Text files return the decoded string in ``content``. Small binary\nfiles return base64-encoded bytes in ``content_base64``. Binary files over\nthe size limit return metadata and an ``error`` field with no inline bytes.\n\nPass ``format=raw`` to receive the file's raw bytes instead of the JSON\nenvelope. This is the path public template pages use to render demo images:\na validated image is served with its pinned image type, anything else is\nserved as a generic download attachment, and every raw response carries\nhardening headers so a file can never execute as an active document in a\nbrowser. Pair ``format=raw`` with ``sha256`` so the URL is content\naddressed: a republished or removed file no longer resolves at a stale\naddress. The default (no ``format``) JSON response is unchanged.\n\nAnonymous callers may fetch files from live (published) template versions.\nOnce a version is unpublished, anonymous reads are denied immediately; the\nliveness check is evaluated per read inside the same transaction, including\nfor ``format=raw``.\n\nWhen ``path`` is omitted this is not a file request: the greedy ``:path``\nsegment swallowed a template whose slug is literally ``files`` (an\n``@handle/files`` URL), so fall through to ordinary template resolution on\nthe reconstructed identifier. Publishing a new template with that slug is\nrejected up front, but legacy templates created before this route existed\nmust still resolve here. (Per-file fetches against such a legacy template\ncannot be disambiguated from this route and are not supported, but those\nrows predate sibling files so their only file is the synthesized SKILL.md,\nwhich the no-path body resolution already returns.)","operationId":"get_template_file_route_templates__template_identifier__files_get","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}},{"name":"path","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Relative path of the file within the template's file tree","title":"Path"},"description":"Relative path of the file within the template's file tree"},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}},{"name":"format","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set to 'raw' to return the file's raw bytes (used to render images on public template pages). Omit for the default structured JSON response.","title":"Format"},"description":"Set to 'raw' to return the file's raw bytes (used to render images on public template pages). Omit for the default structured JSON response."},{"name":"sha256","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Content address of the expected file. When provided, the file is resolved by path and then confirmed to match this value; a stale or mismatched address returns not found.","title":"Sha256"},"description":"Content address of the expected file. When provided, the file is resolved by path and then confirmed to match this value; a stale or mismatched address returns not found."},{"name":"accept","in":"header","required":false,"schema":{"type":"string","default":"application/json","title":"Accept"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{template_identifier}":{"delete":{"summary":"Delete Template Route","description":"Permanently and immediately erase a template you own.\n\nThis is permanent: the template, all its versions, all attached files,\nand all version verification records are removed from the live system at\nonce. There is no recovery path. Use POST .../archive if you want a\nreversible alternative.\n\nEncrypted backups age out within the platform's standard retention window\n(up to three months), so the data is not instantly erased from all systems\neverywhere, but it is no longer accessible through any product surface\nafter this call.\n\nServing gate: if the template is not archived AND has at least one\npublished version (unpublished_at IS NULL), deletion is refused with 409.\nUnpublish the relevant version(s) or archive the template first.\n\nFork severing: forks keep their own content; their parent pointer is set\nto null. lookup_fork_lineage reports the source as permanently deleted.\n\nReturns 200 with ``{template_id, slug, deleted: true}``.","operationId":"delete_template_route_templates__template_identifier__delete","parameters":[{"name":"template_identifier","in":"path","required":true,"schema":{"type":"string","title":"Template Identifier"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Template Route Templates  Template Identifier  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/templates/{identifier}":{"get":{"summary":"Get Template Route","description":"Read a public template to run or fork it.","operationId":"get_template_route_templates__identifier__get","parameters":[{"name":"identifier","in":"path","required":true,"schema":{"type":"string","title":"Identifier"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}},{"name":"accept","in":"header","required":false,"schema":{"type":"string","default":"application/json","title":"Accept"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/teams":{"post":{"summary":"Create Team Route","operationId":"create_team_route_teams_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_CreateTeamIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Team Route Teams Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Teams Route","operationId":"list_teams_route_teams_get","parameters":[{"name":"filter","in":"query","required":false,"schema":{"enum":["mine","member","all"],"type":"string","default":"all","title":"Filter"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Teams Route Teams Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/teams/{team_identifier}":{"delete":{"summary":"Delete Team Route","operationId":"delete_team_route_teams__team_identifier__delete","parameters":[{"name":"team_identifier","in":"path","required":true,"schema":{"type":"string","title":"Team Identifier"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Team Route Teams  Team Identifier  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/teams/{team_identifier}/members":{"get":{"summary":"List Team Members Route","operationId":"list_team_members_route_teams__team_identifier__members_get","parameters":[{"name":"team_identifier","in":"path","required":true,"schema":{"type":"string","title":"Team Identifier"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Team Members Route Teams  Team Identifier  Members Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Add Team Member Route","operationId":"add_team_member_route_teams__team_identifier__members_post","parameters":[{"name":"team_identifier","in":"path","required":true,"schema":{"type":"string","title":"Team Identifier"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_AddMemberIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Add Team Member Route Teams  Team Identifier  Members Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/teams/{team_identifier}/members/{user_identifier}":{"delete":{"summary":"Remove Team Member Route","operationId":"remove_team_member_route_teams__team_identifier__members__user_identifier__delete","parameters":[{"name":"team_identifier","in":"path","required":true,"schema":{"type":"string","title":"Team Identifier"}},{"name":"user_identifier","in":"path","required":true,"schema":{"type":"string","title":"User Identifier"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Remove Team Member Route Teams  Team Identifier  Members  User Identifier  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/teams/{team_identifier}/transfer-ownership":{"post":{"summary":"Transfer Team Ownership Route","operationId":"transfer_team_ownership_route_teams__team_identifier__transfer_ownership_post","parameters":[{"name":"team_identifier","in":"path","required":true,"schema":{"type":"string","title":"Team Identifier"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_TransferOwnershipIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Transfer Team Ownership Route Teams  Team Identifier  Transfer Ownership Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/invitations":{"get":{"summary":"List Invitations Route","operationId":"list_invitations_route_invitations_get","parameters":[{"name":"filter","in":"query","required":false,"schema":{"enum":["received","sent","all"],"type":"string","default":"received","title":"Filter"}},{"name":"state","in":"query","required":false,"schema":{"enum":["pending","all"],"type":"string","default":"pending","title":"State"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Invitations Route Invitations Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/invitations/{invitation_id}/accept":{"post":{"summary":"Accept Invitation Route","operationId":"accept_invitation_route_invitations__invitation_id__accept_post","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Accept Invitation Route Invitations  Invitation Id  Accept Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/invitations/{invitation_id}/decline":{"post":{"summary":"Decline Invitation Route","operationId":"decline_invitation_route_invitations__invitation_id__decline_post","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Decline Invitation Route Invitations  Invitation Id  Decline Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/invitations/{invitation_id}/cancel":{"post":{"summary":"Cancel Invitation Route","operationId":"cancel_invitation_route_invitations__invitation_id__cancel_post","parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Invitation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cancel Invitation Route Invitations  Invitation Id  Cancel Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/me/usage":{"get":{"summary":"Me Usage","description":"Check your usage and remaining credit for the current billing period.\n\nIncludes an ``auto_top_up`` block with your automatic credit top-up\nconfiguration and this month's spend toward it, null if you have never\nconfigured one.","operationId":"me_usage_me_usage_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Me Usage Me Usage Get"}}}}}}},"/image-generators":{"post":{"tags":["image-generators"],"summary":"Deploy an image generator (create or new version)","description":"Create a **caller-owned** image generator or append a new version to one with the same ``name``. First deploy must omit ``expected_version_token``; subsequent deploys must include the latest token returned by deploy, list, or get. Token mismatch returns 409. Creating a new generator whose ``name`` matches an active platform-managed (``scope=system``) generator returns 409. Returns ``{generator_id, name, current_version, version, version_token, status, provider, model, generation_contract, config_hash}``.","operationId":"deploy_image_generator_route_image_generators_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployImageGeneratorInput"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Deploy Image Generator Route Image Generators Post"}}}},"400":{"description":"Validation error: unpriceable model or bad contract."},"401":{"description":"Authentication required."},"409":{"description":"Conflict: missing or mismatched ``expected_version_token``, or name reserved for a platform-managed generator."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["image-generators"],"summary":"List active image generators visible to the caller","description":"Returns ``{items: [...], next_cursor: str | null}`` with one entry per non-revoked image generator the caller owns. Platform ``scope=system`` generators never appear here. Anonymous callers get an empty list.","operationId":"list_image_generators_route_image_generators_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Image Generators Route Image Generators Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image-generators/{generator_id}":{"get":{"tags":["image-generators"],"summary":"Get one image generator version (config, contract, params)","description":"Defaults to the current version; pass ``?version=N`` to pin. Returns the full deploy-time payload plus ``config_hash`` for drift detection. ``generator_id`` must be a UUID. Platform-managed (``scope=system``), unauthorized, or revoked generators are always 404.","operationId":"get_image_generator_route_image_generators__generator_id__get","parameters":[{"name":"generator_id","in":"path","required":true,"schema":{"type":"string","title":"Generator Id"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Image Generator Route Image Generators  Generator Id  Get"}}}},"401":{"description":"Authentication required."},"404":{"description":"Image generator not found, revoked, or not owned by caller."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["image-generators"],"summary":"Revoke an image generator","description":"Sets ``status='revoked'`` and ``revoked_at`` for **caller-owned** ``scope=user`` generators only (UUID). Platform ``scope=system`` generators are always 404. The generator disappears from list/get/run for the owner; existing run rows are retained. Irreversible; replace by deploying a fresh generator under a new name.","operationId":"revoke_image_generator_route_image_generators__generator_id__delete","parameters":[{"name":"generator_id","in":"path","required":true,"schema":{"type":"string","title":"Generator Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revoke Image Generator Route Image Generators  Generator Id  Delete"}}}},"401":{"description":"Authentication required."},"404":{"description":"Image generator not found, already revoked, or not owned by caller."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image-generators/{generator_id}/runs":{"post":{"tags":["image-generators"],"summary":"Generate one or more images from a prompt using a deployed generator.","description":"Generates one or more images using the referenced generator. Path ``generator_id`` is a UUID, ``uuid@version`` to pin a version, or ``system:<tier>`` for platform-managed quality tiers. Anonymous callers may invoke a system tier or a UUID iff it appears in some live ``template_versions.image_generator_snapshots``; spend is gated by the credit ledger. The ``model`` body field (authenticated one-off) is not usable from published templates or by anonymous callers. Caller-shape errors return 400; runtime and provider errors return 201 with ``status='error'`` and an ``error_code`` of ``provider_error``, ``runtime_error``, or ``timeout``. Returns ``{run_id, model_tier_or_model, image_url, image_urls, width, height, num_images, cost_usd, duration_ms, status, created_at, error_code, error_message}``.","operationId":"generate_image_route_image_generators__generator_id__runs_post","parameters":[{"name":"generator_id","in":"path","required":true,"schema":{"type":"string","title":"Generator Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_GenerateImageBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Generate Image Route Image Generators  Generator Id  Runs Post"}}}},"400":{"description":"Caller-shape error (bad generator ref, contract mismatch, or model path rejected for anonymous caller)."},"404":{"description":"Generator not found, not publicly runnable, or referenced skill not visible to caller."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image-generators/{generator_id}/permanent":{"delete":{"tags":["image-generators"],"summary":"Permanently delete an image generator","description":"Permanently and immediately erase a **caller-owned** ``scope=user`` image generator. The generator, all its versions (provider config, model, parameters), all run records, and all anonymous run records are removed from the live system at once. There is no recovery path. Use ``DELETE /{generator_id}`` (revoke) to deactivate without erasing, keeping the audit trail intact. Serving gate: if any live published template version carries a snapshot that references this generator, deletion is refused (409). Unpublish the relevant template version(s) first, then retry. Platform ``scope=system`` generators and another user's generators always surface as 404. Encrypted backups age out within the platform's standard retention window (up to three months), so the data is not instantly erased from all systems everywhere, but it is no longer accessible through any product surface after this call. Returns ``{generator_id, name, deleted: true}``.","operationId":"delete_image_generator_route_image_generators__generator_id__permanent_delete","parameters":[{"name":"generator_id","in":"path","required":true,"schema":{"type":"string","title":"Generator Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Image Generator Route Image Generators  Generator Id  Permanent Delete"}}}},"401":{"description":"Authentication required."},"404":{"description":"Image generator not found, not owned by caller, or platform-managed (scope=system)."},"409":{"description":"Generator is referenced by a live published template version. Unpublish the template version(s) first."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/i/{token_ext}":{"get":{"summary":"Serve Image Route","description":"Display a hosted image from its serving link.\n\nThe URL segment after ``/i/`` is parsed as ``{token}.{ext}``; the\nextension is cosmetic and is never used to derive the Content-Type.\nThe token (everything before the first dot) identifies the image row.\n\nVisibility rules:\n- ``public``: served to any caller, including anonymous. A malformed or\n  stale Authorization header does not block a public image; it is treated\n  as an anonymous request.\n- ``private``: requires an authenticated caller who owns the image, OR a\n  caller that presents the image's capability secret as the ``k`` query\n  parameter (the owner's durable, forwardable view link). Anonymous callers\n  with neither receive 401; authenticated non-owners receive 404.","operationId":"serve_image_route_i__token_ext__get","parameters":[{"name":"token_ext","in":"path","required":true,"schema":{"type":"string","title":"Token Ext"}},{"name":"k","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"K"}},{"name":"if-none-match","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"If-None-Match"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"head":{"summary":"Serve Image Route","description":"Display a hosted image from its serving link.\n\nThe URL segment after ``/i/`` is parsed as ``{token}.{ext}``; the\nextension is cosmetic and is never used to derive the Content-Type.\nThe token (everything before the first dot) identifies the image row.\n\nVisibility rules:\n- ``public``: served to any caller, including anonymous. A malformed or\n  stale Authorization header does not block a public image; it is treated\n  as an anonymous request.\n- ``private``: requires an authenticated caller who owns the image, OR a\n  caller that presents the image's capability secret as the ``k`` query\n  parameter (the owner's durable, forwardable view link). Anonymous callers\n  with neither receive 401; authenticated non-owners receive 404.","operationId":"serve_image_route_i__token_ext__get","parameters":[{"name":"token_ext","in":"path","required":true,"schema":{"type":"string","title":"Token Ext"}},{"name":"k","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"K"}},{"name":"if-none-match","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"If-None-Match"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/images":{"post":{"tags":["images"],"summary":"Upload Image","description":"Upload an image and return the hosted image record.\n\nThe file must be a PNG, JPEG, WebP, or GIF. Accepted visibility values\nare ``public`` and ``private`` (default ``private``).","operationId":"upload_image_images_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_image_images_post"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Upload Image Images Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["images"],"summary":"List Images Route","description":"List hosted images owned by the caller, with optional filters.","operationId":"list_images_route_images_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},{"name":"visibility","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Images Route Images Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/images/{image_id}":{"get":{"tags":["images"],"summary":"Get Image Route","description":"Fetch a hosted image by id. Caller must own it.","operationId":"get_image_route_images__image_id__get","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Image Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Image Route Images  Image Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["images"],"summary":"Update Image Route","description":"Update visibility, TTL, or the private view link of a hosted image.\n\nCaller must own it.\n\n``ttl_seconds`` and ``permanent`` are mutually exclusive: providing both\nreturns a validation error. ``permanent=true`` clears the expiry so the\nimage lives indefinitely. ``ttl_seconds`` sets a new expiry relative to now.\nOmitting both leaves the current expiry unchanged.\n\n``rotate_view_secret=true`` issues a fresh private view link and invalidates\nevery link shared earlier for this image (un-share). For a private image the\nreturned ``url`` is the current view link.","operationId":"update_image_route_images__image_id__patch","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Image Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_UpdateImageBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Update Image Route Images  Image Id  Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["images"],"summary":"Delete Image Route","description":"Hard-delete a hosted image. Caller must own it.","operationId":"delete_image_route_images__image_id__delete","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Image Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/notifications/unsubscribe":{"get":{"summary":"Get Unsubscribe Confirm","description":"Show the unsubscribe confirmation page. Mutates nothing.\n\nA GET request (including automated link prefetches and email scanners)\nmust never trigger an opt-out. Only the subsequent POST does.\n\nAn invalid or missing token still returns a page (neutral error) rather\nthan an error status so that automated probes get no useful oracle signal.","operationId":"get_unsubscribe_confirm_notifications_unsubscribe_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Post Unsubscribe","description":"Opt the user out of all collaboration notifications.\n\nThe opt-out is global: it suppresses skill-share emails as well as team\ninvitations and skill/template ownership-transfer emails.\n\nAccepts the token from the form body (preferred, from the confirm page)\nor from the query string (fallback for deep-link POSTs). Idempotent.","operationId":"post_unsubscribe_notifications_unsubscribe_post","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_post_unsubscribe_notifications_unsubscribe_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/notifications/resubscribe":{"post":{"summary":"Post Resubscribe","description":"Re-enable all collaboration notifications for the user. Idempotent.","operationId":"post_resubscribe_notifications_resubscribe_post","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_post_resubscribe_notifications_resubscribe_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/referrals/me":{"get":{"summary":"Referral Status Route","description":"Check your referral standing: your code, referrals you have made, and bonus\ncredits earned.","operationId":"referral_status_route_referrals_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Referral Status Route Referrals Me Get"}}}}}}},"/referrals/redeem":{"post":{"summary":"Redeem Referral Route","description":"Redeem a referral code to claim new-user bonus credits.","operationId":"redeem_referral_route_referrals_redeem_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RedeemRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Redeem Referral Route Referrals Redeem Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/verifiers":{"post":{"tags":["verifiers"],"summary":"Deploy a verifier (create or new version)","description":"Create a **caller-owned** verifier or append a new version to one with the same ``name``. First deploy must omit ``expected_version_token``; subsequent deploys must include the latest token returned by deploy, list, or get. Token mismatch returns 409. Creating a new verifier whose ``name`` matches an active platform-managed (``scope=system``) verifier returns 409. Returns ``{verifier_id, name, current_version, version, version_token, status, input_contract, config_hash}``.","operationId":"deploy_verifier_route_verifiers_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeployVerifierInput"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Deploy Verifier Route Verifiers Post"}}}},"400":{"description":"Validation error: bad contract, fields, or examples."},"401":{"description":"Authentication required."},"409":{"description":"Conflict: missing or mismatched ``expected_version_token``, or name reserved for a platform-managed verifier."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["verifiers"],"summary":"List active verifiers visible to the caller","description":"Returns ``{items: [...], next_cursor: str | null}`` with one entry per non-revoked verifier the caller owns or can access through skill-derived grants. Platform ``scope=system`` verifiers never appear here. Anonymous callers get an empty list.","operationId":"list_verifiers_route_verifiers_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Verifiers Route Verifiers Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/verifiers/{verifier_id}":{"get":{"tags":["verifiers"],"summary":"Get one verifier version (criterion, contract, calibration)","description":"Defaults to the current version; pass ``?version=N`` to pin. Returns the full deploy-time payload plus ``config_hash`` for drift detection. ``verifier_id`` accepts UUID string or accessible user-scope verifier name. Any caller who can reach the verifier can read it: the owner and skill grantees at any role (a view/exec grantee can read, not only run). Platform-managed (``scope=system``), unauthorized, or revoked verifiers are always 404.","operationId":"get_verifier_version_route_verifiers__verifier_id__get","parameters":[{"name":"verifier_id","in":"path","required":true,"schema":{"type":"string","title":"Verifier Id"}},{"name":"version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Version"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Verifier Version Route Verifiers  Verifier Id  Get"}}}},"401":{"description":"Authentication required."},"404":{"description":"Verifier not found, revoked, or not accessible to caller."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["verifiers"],"summary":"Revoke a verifier","description":"Sets ``status=\"revoked\"`` and ``revoked_at`` for **caller-owned** ``scope=user`` verifiers only (UUID or name). Platform ``scope=system`` verifiers reject as 404. The verifier disappears from list/get/run for the owner; existing run rows are retained. Irreversible; replace by deploying a fresh verifier under a new name.","operationId":"revoke_verifier_route_verifiers__verifier_id__delete","parameters":[{"name":"verifier_id","in":"path","required":true,"schema":{"type":"string","title":"Verifier Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revoke Verifier Route Verifiers  Verifier Id  Delete"}}}},"401":{"description":"Authentication required."},"404":{"description":"Verifier not found, already revoked, or not owned by caller."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/verifiers/{verifier_id}/runs":{"post":{"tags":["verifiers"],"summary":"Run a verifier to check whether an output meets its criterion.","description":"Runs the judge against ``inputs`` (and optional ``media_url``). Path ``verifier_id`` is a Verifier UUID, or ``system:<name>`` for platform-managed verifiers. Anonymous callers may run a Verifier UUID iff it appears in some live ``template_versions.verifier_snapshots`` (publicly-runnable gate); spend is gated by the credit ledger. Caller-shape errors return 400 with no row written; runtime errors return 201 with ``status=\"error\"`` and an ``error_code`` of ``runtime_error``, ``verifier_unavailable``, or ``timeout``. Returns ``{verifier_run_id, anonymous_verifier_run_id, verifier_id, version, status, passed, reasoning, duration_ms, created_at}`` (one of ``verifier_run_id`` or ``anonymous_verifier_run_id`` populated). A successful run attributed to a skill you own also echoes that skill's ``skill_id``.","operationId":"run_verifier_route_verifiers__verifier_id__runs_post","parameters":[{"name":"verifier_id","in":"path","required":true,"schema":{"type":"string","title":"Verifier Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_RunVerifierBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Run Verifier Route Verifiers  Verifier Id  Runs Post"}}}},"400":{"description":"Caller-shape error (bad inputs, missing or excess fields, wrong media)."},"404":{"description":"Verifier or referenced skill not visible to caller."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/verifiers/{verifier_id}/permanent":{"delete":{"tags":["verifiers"],"summary":"Permanently delete a verifier","description":"Permanently and immediately erase a **caller-owned** ``scope=user`` verifier. The verifier, all its versions (criterion, calibration examples, input contracts), all run records, and all access grants are removed from the live system at once. There is no recovery path. Use ``DELETE /{verifier_id}`` (revoke) to deactivate without erasing, keeping the audit trail intact. Serving gate: if any live published template version carries a snapshot that references this verifier, deletion is refused (409). Unpublish the relevant template version(s) first, then retry. Platform ``scope=system`` verifiers and another user's verifiers always surface as 404. Encrypted backups age out within the platform's standard retention window (up to three months), so the data is not instantly erased from all systems everywhere, but it is no longer accessible through any product surface after this call. Returns ``{verifier_id, name, deleted: true}``.","operationId":"delete_verifier_route_verifiers__verifier_id__permanent_delete","parameters":[{"name":"verifier_id","in":"path","required":true,"schema":{"type":"string","title":"Verifier Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Verifier Route Verifiers  Verifier Id  Permanent Delete"}}}},"401":{"description":"Authentication required."},"404":{"description":"Verifier not found, not owned by caller, or platform-managed (scope=system)."},"409":{"description":"Verifier is referenced by a live published template version. Unpublish the template version(s) first."},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/checkout":{"post":{"summary":"Billing Checkout","description":"Start a Pro subscription and get a hosted checkout link.\n\nReturns ``{\"checkout_url\": ...}``. Errors: ``billing_not_enabled`` when\nself-service billing is not configured, ``already_subscribed`` when the\ncaller already has an active subscription.","operationId":"billing_checkout_billing_checkout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Checkout Billing Checkout Post"}}}}}}},"/billing/subscription/cancel":{"post":{"summary":"Billing Subscription Cancel","description":"Cancel your Pro subscription at the end of the current billing period.\n\nReturns ``{\"status\": ..., \"access_until\": ...}`` where ``access_until`` is\nthe ISO-8601 end of the paid period, or null. Access continues until then.\nError: ``no_active_subscription`` when there is nothing to cancel.","operationId":"billing_subscription_cancel_billing_subscription_cancel_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Subscription Cancel Billing Subscription Cancel Post"}}}}}}},"/billing/portal":{"post":{"summary":"Billing Portal","description":"Get a link to the billing portal to manage your subscription and payment method.\n\nReturns ``{\"portal_url\": ...}``. Error: ``billing_not_enabled`` when\nself-service billing is not configured.","operationId":"billing_portal_billing_portal_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Portal Billing Portal Post"}}}}}}},"/billing/credits/purchase":{"post":{"summary":"Billing Credits Purchase","description":"Buy a one-time credit top-up.\n\nCharges the default payment method on file when one exists and returns\n``{\"status\": \"charged\", \"amount_usd\": ..., \"new_balance_usd\": ...}``.\nOtherwise returns ``{\"status\": \"checkout_required\", \"checkout_url\": ...}``\nfor a hosted checkout session so the purchase can complete interactively.\nErrors: ``billing_not_enabled`` when self-service billing is not\nconfigured, ``invalid_amount`` when the requested amount falls outside\nthe allowed range.","operationId":"billing_credits_purchase_billing_credits_purchase_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_PurchaseCreditsIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Credits Purchase Billing Credits Purchase Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/auto-top-up":{"get":{"summary":"Billing Auto Top Up Get","description":"Check your automatic credit top-up configuration and this month's spend toward it.\n\nReturns ``{\"enabled\": ..., \"threshold_usd\": ..., \"amount_usd\": ...,\n\"monthly_cap_usd\": ..., \"monthly_spent_usd\": ..., \"status\": ...,\n\"last_failure_reason\": ...}``. A caller who has never configured\nautomatic top-ups gets a disabled default block, not an error.","operationId":"billing_auto_top_up_get_billing_auto_top_up_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Auto Top Up Get Billing Auto Top Up Get"}}}}}},"put":{"summary":"Billing Auto Top Up Put","description":"Turn on automatic credit top-ups and set (or update) their terms.\n\nRequires a default payment method already on file: make a manual credit\npurchase first to save one. Returns the resolved config block, the same\nshape as the GET route. Errors: ``no_payment_method`` (409) when no\ndefault payment method is on file, ``invalid_amount`` (400) when the\namount, threshold, or monthly cap falls outside the allowed range.\nRe-running this also clears any previously failed automatic top-up\nstate, acting as a retry.","operationId":"billing_auto_top_up_put_billing_auto_top_up_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_ConfigureAutoTopUpIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Auto Top Up Put Billing Auto Top Up Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Billing Auto Top Up Delete","description":"Turn off automatic credit top-ups.\n\nReturns the config block with ``enabled`` false. Clears any stored\nfailure state; leaves the previously configured amount, threshold, and\nmonthly cap in place for a later re-enable.","operationId":"billing_auto_top_up_delete_billing_auto_top_up_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Billing Auto Top Up Delete Billing Auto Top Up Delete"}}}}}}},"/webhooks/stripe":{"post":{"summary":"Stripe Webhook","description":"Receive subscription lifecycle notifications from the payment provider.\n\nUnauthenticated by design: every delivery is authenticated by verifying the\nStripe signature over the raw request body. A verification failure returns\n``400`` before any database work begins.","operationId":"stripe_webhook_webhooks_stripe_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"ArchiveTemplateInput":{"properties":{"archive_reason":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Archive Reason"}},"type":"object","title":"ArchiveTemplateInput","description":"Optional body for ``POST /v1/templates/{template_identifier}/archive``.\n\n``archive_reason`` is a short human-readable note stored on\n``templates.archive_reason``. Empty body is accepted (FastAPI passes\n``None`` to the route, which then constructs a default)."},"AuthStartIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"AuthStartIn"},"Body_post_resubscribe_notifications_resubscribe_post":{"properties":{"token":{"type":"string","title":"Token","default":""}},"type":"object","title":"Body_post_resubscribe_notifications_resubscribe_post"},"Body_post_unsubscribe_notifications_unsubscribe_post":{"properties":{"token":{"type":"string","title":"Token","default":""}},"type":"object","title":"Body_post_unsubscribe_notifications_unsubscribe_post"},"Body_upload_image_images_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"visibility":{"type":"string","title":"Visibility","default":"private"},"ttl_seconds":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Ttl Seconds"}},"type":"object","required":["file"],"title":"Body_upload_image_images_post"},"CreateKeyIn":{"properties":{"name":{"type":"string","maxLength":64,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"CreateKeyIn","description":"Request body for ``POST /v1/api-keys``."},"DeployImageGeneratorInput":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"pattern":"^[a-z0-9][a-z0-9-]*$","title":"Name","description":"Image generator name, unique per owner among non-revoked generators. Lowercase letters, digits, and hyphens; no spaces."},"description":{"type":"string","maxLength":1024,"minLength":1,"title":"Description","description":"Short summary of what this image generator produces."},"provider":{"type":"string","const":"fal","title":"Provider","description":"Generation provider backing this image generator.","default":"fal"},"model":{"type":"string","maxLength":256,"minLength":1,"title":"Model","description":"Provider endpoint identifier for the image model (e.g. a slug such as ``provider-org/model-name``). Must resolve to a known image endpoint with an authoritative per-image price."},"generation_contract":{"type":"string","enum":["text_to_image","image_to_image"],"title":"Generation Contract","description":"Input shape at generation time. ``text_to_image``: generates an image from a text prompt only. ``image_to_image``: requires a reference image URL in addition to a prompt."},"default_params":{"additionalProperties":true,"type":"object","title":"Default Params","description":"Default generation parameters merged with per-call overrides at run time (e.g. image size, safety settings). Callers may override individual keys via ``param_overrides`` on ``generate_image``."},"expected_version_token":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Expected Version Token","description":"Optimistic-concurrency token. Required when re-deploying an existing generator to confirm you have seen the latest version (get it from ``deploy_image_generator``, ``list_image_generators``, or ``get_image_generator``). Must be omitted on first deploy. Mismatch returns a Conflict with the current token."}},"type":"object","required":["name","description","model","generation_contract"],"title":"DeployImageGeneratorInput","description":"Payload for ``deploy_image_generator``: create a new image generator or\nappend a new version to an existing one (owner-scoped, name-uniqueness\nwithin owner)."},"DeployVerifierInput":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"pattern":"^[a-z0-9][a-z0-9-]*$","title":"Name","description":"Verifier name, unique per owner among non-revoked verifiers. Lowercase letters, digits, and hyphens; no spaces."},"description":{"type":"string","maxLength":1024,"minLength":1,"title":"Description","description":"Short human-readable summary of what the verifier judges."},"criterion":{"type":"string","maxLength":20000,"minLength":1,"title":"Criterion","description":"The rubric prose the judge applies. Write it as a direct instruction to the judge (e.g. 'Return passed=true when ...')."},"input_contract":{"$ref":"#/components/schemas/InputContract","description":"Shape of inputs at run time: ``text``, ``text_image``, or ``image``. Drives signature shape and what ``run_verifier`` accepts."},"input_fields":{"items":{"type":"string"},"type":"array","title":"Input Fields","description":"Names of the text inputs the judge sees. Required for ``text`` and ``text_image``; must be empty for ``image``. Names are deduplicated case-insensitively. ``run_verifier`` rejects callers whose ``inputs`` keys do not match this list exactly."},"few_shot_examples":{"items":{"$ref":"#/components/schemas/FewShotExample"},"type":"array","title":"Few Shot Examples","description":"Labeled calibration examples (3 to 10 are typical). Each example must satisfy the contract: ``text`` examples carry only ``inputs``; ``text_image`` carries both ``inputs`` and ``media_url``; ``image`` carries only ``media_url``."},"model_settings":{"$ref":"#/components/schemas/ModelConfig","description":"Judge LM settings. Only ``model`` and ``reasoning_effort`` are honored; see ``ModelConfig``."},"expected_version_token":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Expected Version Token","description":"Optimistic-concurrency token. Required when re-deploying an existing verifier to confirm you've seen the latest version (get it from ``deploy_verifier``, ``list_verifiers``, or ``get_verifier``). Must be omitted on first deploy. Mismatch returns a Conflict with the current token."}},"type":"object","required":["name","description","criterion","input_contract"],"title":"DeployVerifierInput","description":"Payload for ``deploy_verifier``: create a new verifier or append a new\nversion to an existing one (owner-scoped, name-uniqueness within owner)."},"DeprecateTemplateVersionInput":{"properties":{"message":{"type":"string","maxLength":1000,"minLength":1,"title":"Message"}},"type":"object","required":["message"],"title":"DeprecateTemplateVersionInput","description":"Input for ``POST /v1/templates/{template_identifier}/versions/{version}/deprecate``.\n\n``message`` is required and last-write-wins on\n``template_versions.deprecation_message``."},"ExchangeIn":{"properties":{"hostname":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hostname"}},"type":"object","title":"ExchangeIn"},"FewShotExample":{"properties":{"inputs":{"additionalProperties":{"type":"string"},"type":"object","title":"Inputs","description":"Map of ``input_fields`` name to value. Required for ``text`` and ``text_image`` contracts, must be empty for ``image``."},"media_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Media Url","description":"Public HTTPS image URL. Required for ``text_image`` and ``image`` contracts, rejected for ``text``."},"passed":{"type":"boolean","title":"Passed","description":"Ground-truth label: did this example satisfy the criterion?"},"reasoning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning","description":"Optional rationale shown to the judge alongside the label."}},"additionalProperties":false,"type":"object","required":["passed"],"title":"FewShotExample","description":"A single labeled example attached to a verifier version. The runtime\nshows these to the judge as calibration demonstrations."},"FileEntry":{"properties":{"path":{"type":"string","maxLength":1024,"title":"Path","description":"Normalized relative POSIX path for this file within the bundle (e.g. 'references/rubric.md'). Must not be empty, absolute, contain '..' or '.' segments, empty segments (a trailing slash or 'foo//bar'), backslashes, or ASCII control characters."},"executable":{"type":"boolean","title":"Executable","description":"Whether the file should be marked executable when extracted.","default":false},"purpose":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Purpose","description":"Short label describing the file's role in the skill (optional)."},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"Inline file content as a UTF-8 text string, stored verbatim. Use 'content_base64' for binary files. Mutually exclusive with 'content_base64' and 'sha256'."},"content_base64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Base64","description":"Inline binary file content as base64-encoded bytes, decoded on receipt. Mutually exclusive with 'content' and 'sha256'."},"sha256":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sha256","description":"Hex SHA-256 digest referencing a blob already known to the registry. Mutually exclusive with 'content' and 'content_base64'."}},"type":"object","required":["path"],"title":"FileEntry","description":"A single file in a skill bundle.\n\nExactly one of ``content``, ``content_base64``, or ``sha256`` must be\nprovided. Provide ``content`` to inline a UTF-8 text file (it is stored\nverbatim as the given text; it is never reinterpreted as base64). Provide\n``content_base64`` to inline a binary file (base64-encoded bytes, decoded\non receipt). Provide ``sha256`` to reference a blob the registry can\nalready read."},"FilePatchEntry":{"properties":{"path":{"type":"string","maxLength":1024,"title":"Path","description":"Normalized relative POSIX path for the file being changed (e.g. 'references/rubric.md'). Must not be empty, absolute, contain '..' or '.' segments, empty segments (a trailing slash or 'foo//bar'), backslashes, or ASCII control characters."},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content","description":"New inline file content as a UTF-8 text string, stored verbatim. Use 'content_base64' for binary files. Mutually exclusive with 'content_base64' and 'sha256'."},"content_base64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content Base64","description":"New inline binary file content as base64-encoded bytes, decoded on receipt. Mutually exclusive with 'content' and 'sha256'."},"sha256":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sha256","description":"Hex SHA-256 digest referencing a blob already known to the registry, used as the file's new content. Mutually exclusive with 'content' and 'content_base64'."},"executable":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Executable","description":"Whether the file should be marked executable when extracted. Leave unset to keep the file's current executable setting unchanged; set it explicitly only to change that setting."},"purpose":{"anyOf":[{"type":"string","maxLength":1024},{"type":"null"}],"title":"Purpose","description":"Short label describing the file's role in the skill. Leave unset to keep the file's current label unchanged; set it explicitly only to change that label."}},"type":"object","required":["path"],"title":"FilePatchEntry","description":"A single file change in a patch to an existing skill's file tree.\n\nExactly one of ``content``, ``content_base64``, or ``sha256`` must be\nprovided, giving the new content for this path. Provide ``content`` to\ninline a UTF-8 text file (stored verbatim, never reinterpreted as\nbase64). Provide ``content_base64`` to inline a binary file\n(base64-encoded bytes, decoded on receipt). Provide ``sha256`` to\nreference a blob the registry can already read.\n\nUnlike a full bundle snapshot, a patch only ever changes what it names:\nany path not mentioned in the patch is left alone, and within a\nmentioned path, ``executable`` and ``purpose`` default to ``None``,\nmeaning \"carry the current value forward\" rather than \"this file has no\nsuch value.\" Set either field explicitly to change it; leave it unset to\nkeep whatever the file already had."},"ForkTemplateInput":{"properties":{"identifier":{"type":"string","maxLength":128,"minLength":1,"title":"Identifier"},"version":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Version"},"name":{"anyOf":[{"type":"string","maxLength":128,"minLength":1,"pattern":"^[a-z0-9][a-z0-9-]*$"},{"type":"null"}],"title":"Name"}},"type":"object","required":["identifier"],"title":"ForkTemplateInput","description":"Input for ``fork_template``.\n\n``identifier`` accepts a UUID string, ``@handle/slug``, or\n``@handle/slug@vN``. ``version`` lets the caller pin to an older\npublished version; default is the latest live version. ``name`` lets\nthe caller override the fork's slug; default is the template slug with\na numeric suffix on caller-namespace collision."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InputContract":{"type":"string","enum":["text","text_image","image"],"title":"InputContract","description":"Shape of inputs the verifier judges.\n\n``text``: text fields only (``input_fields`` required, ``media_url`` rejected).\n``text_image``: text fields plus one image (both required at run time).\n``image``: a single image only (``input_fields`` must be empty, ``media_url`` required)."},"ModelConfig":{"properties":{"model":{"type":"string","maxLength":128,"minLength":1,"title":"Model","description":"Model identifier for the judge LLM (e.g. ``openai/gpt-5.4-mini``, ``anthropic/claude-sonnet-4-6``). Must be one of the platform's supported models. Defaults to the platform's standard judge model."},"reasoning_effort":{"type":"string","enum":["low","medium","high","xhigh"],"title":"Reasoning Effort","description":"Reasoning budget hint forwarded to providers that accept it. Silently dropped for models that don't expose ``reasoning_effort``.","default":"medium"}},"additionalProperties":false,"type":"object","title":"ModelConfig","description":"Verifier judge LM configuration. Only ``model`` and ``reasoning_effort``\nare honored; any other field is rejected so callers can't quietly leak\nsampling knobs (temperature, max_tokens, etc.) into the judge."},"PublishTemplateVersionInput":{"properties":{"skill_id":{"type":"string","maxLength":512,"minLength":1,"title":"Skill Id","description":"Skill UUID (string) or slug (same as the skill's ``name``)."},"release_notes":{"anyOf":[{"type":"string","maxLength":4096},{"type":"null"}],"title":"Release Notes"}},"type":"object","required":["skill_id"],"title":"PublishTemplateVersionInput","description":"Input for ``publish_template_version``."},"RedeemRequest":{"properties":{"code":{"type":"string","title":"Code"}},"type":"object","required":["code"],"title":"RedeemRequest","description":"Request body for redeeming a referral code."},"SaveWorkflowInput":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"pattern":"^[a-z0-9][a-z0-9-]*$","title":"Name","description":"Skill name in kebab-case (lowercase letters, digits, and hyphens). Doubles as the slug and is unique within your namespace."},"skill_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Skill Id","description":"Target a specific skill to edit. Omit it to save in your own namespace: the call updates your own skill of this name, or creates a new one. Supply it to update a specific skill you own or have edit access to; ``name`` must match that skill's name."},"description":{"type":"string","maxLength":1024,"minLength":1,"title":"Description","description":"One-sentence summary of what the skill does and when to use it. This is the text that decides when the skill fires."},"body":{"type":"string","minLength":1,"title":"Body","description":"The skill runbook as markdown: the full set of instructions an agent follows on the user's behalf."},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","description":"Discovery tags surfaced when listing and searching skills. When omitted on an update, the existing tags are preserved; send an empty list to clear them."},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome","description":"The business outcome this skill is meant to drive, surfaced as a discovery facet. When omitted on an update, the existing outcome is preserved; send null to clear it."},"verifiers":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Verifiers","description":"Semantic verifier references this skill invokes on agent output. Each entry names a deployed verifier by id or id@version. When omitted on an update, the existing list is preserved unchanged."},"image_generators":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Image Generators","description":"Image generator references for this skill. Each entry binds a local name (used in generation steps) to a generator reference. The reference is either a platform-managed quality tier (``system:<tier>``) or a specific deployed generator (``uuid`` or ``uuid@version``). When omitted on an update, the existing list is preserved unchanged."},"files":{"anyOf":[{"items":{"$ref":"#/components/schemas/FileEntry"},"type":"array"},{"type":"null"}],"title":"Files","description":"Sibling files bundled with the skill. Include a 'demo/README.md' writeup with images referenced by relative path inside 'demo/' to render a visual demo on the public template page once the skill is published as a template. A supplied list is a full snapshot: any path you do not include is deleted. Omitting the field entirely preserves the existing tree unchanged; to change specific files without resending the rest, use `update_skill_files` instead."},"expected_version_token":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Expected Version Token","description":"Concurrency token from the latest known version, required when editing an existing skill so a stale overwrite is rejected. Omit when creating a new skill."},"source":{"anyOf":[{"type":"string","enum":["manual","teach","optimization","description_optimization","audit"]},{"type":"null"}],"title":"Source","description":"Attributes the saved version to how it was produced ('manual', 'teach', 'optimization', 'description_optimization', or 'audit'); omit to leave it unset."}},"type":"object","required":["name","description","body","expected_version_token"],"title":"SaveWorkflowInput","description":"Publish-skill payload aligned with the Claude Code skills convention.\n\nRequired top-level fields mirror a Claude Code ``SKILL.md`` frontmatter:\n``name`` (kebab-case handle) and ``description`` (one-sentence summary).\n``outcome`` and ``tags`` are top-level discovery facets surfaced by\n``list_skills``; everything else lives in the ``body`` and is opaque\nto the registry.\n\nSkills are always private to the caller. Public sharing is the\n``templates`` surface (``publish_template_version`` / ``fork_template``);\nthere is no ``visibility`` knob on a skill row.\n\nUnknown fields are silently dropped (``extra=\"ignore\"``). Fields such as\n``manifest``, ``visibility``, and ``kpi`` do not cause validation errors\nand are simply ignored.\n\nThe server accepts both ``slug`` and ``name`` as input for the skill\nhandle. Responses return both ``name`` and ``slug`` fields with identical\nvalues."},"SearchTemplatesInput":{"properties":{"query":{"type":"string","minLength":1,"title":"Query","description":"Natural-language description of the template you are looking for."},"filter":{"type":"string","enum":["mine","all"],"title":"Filter","description":"Which templates to search: 'mine' for ones you published, or 'all' for the public catalog.","default":"all"},"limit":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Limit","description":"Maximum number of ranked results to return (1 to 10).","default":5}},"type":"object","required":["query"],"title":"SearchTemplatesInput","description":"Natural-language search request over public or owned templates."},"SearchWorkflowsInput":{"properties":{"query":{"type":"string","minLength":1,"title":"Query","description":"Natural-language description of the skill you are looking for."},"filter":{"type":"string","enum":["mine","all","shared-with-me"],"title":"Filter","description":"Which skills to search: 'mine' for ones you own, 'shared-with-me' for ones shared with you, or 'all' for both.","default":"all"},"tag":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tag","description":"Restrict results to skills carrying this tag; omit to search every tag."},"limit":{"type":"integer","maximum":10.0,"minimum":1.0,"title":"Limit","description":"Maximum number of ranked results to return (1 to 10).","default":5}},"type":"object","required":["query"],"title":"SearchWorkflowsInput","description":"Natural-language search request over skills visible to the caller."},"TransferTemplateOwnershipInput":{"properties":{"new_owner_user_id_or_email":{"type":"string","minLength":1,"title":"New Owner User Id Or Email"}},"type":"object","required":["new_owner_user_id_or_email"],"title":"TransferTemplateOwnershipInput","description":"Input for ``POST /v1/templates/{template_identifier}/transfer-ownership``.\n\nMirrors ``transfer_skill_ownership`` body shape: a UUID string or\nan email address resolves to a user. Team targets are rejected at the\nservice layer with ``InvalidGranteeType``."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"code":{"type":"string","title":"Code"}},"type":"object","required":["email","code"],"title":"VerifyIn"},"_AddMemberIn":{"properties":{"user_identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Identifier"},"user_id_or_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id Or Email"}},"type":"object","title":"_AddMemberIn"},"_ConfigureAutoTopUpIn":{"properties":{"amount_usd":{"type":"integer","title":"Amount Usd","description":"Amount to add, in whole US dollars, each time your balance drops below the threshold."},"threshold_usd":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Threshold Usd","description":"Balance, in whole US dollars, that triggers an automatic top-up. Defaults to the top-up amount when omitted."},"monthly_cap_usd":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Monthly Cap Usd","description":"Maximum total, in whole US dollars, automatic top-ups can spend in a calendar month. Defaults to four times the top-up amount when omitted."}},"type":"object","required":["amount_usd"],"title":"_ConfigureAutoTopUpIn","description":"Request body for ``PUT /billing/auto-top-up``."},"_CreateTeamIn":{"properties":{"handle":{"type":"string","maxLength":40,"minLength":3,"title":"Handle"}},"type":"object","required":["handle"],"title":"_CreateTeamIn"},"_GenerateImageBody":{"properties":{"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"Concrete image model identifier for an authenticated one-off generation. Not usable from published templates or by anonymous callers. When set, the path ``generator_id`` is ignored and this value is used directly. Mutually exclusive with the path generator."},"prompt":{"type":"string","minLength":1,"title":"Prompt","description":"Text description of the image to generate."},"reference_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Image Url","description":"Public HTTP or HTTPS URL of the reference image. Required for ``image_to_image`` generators; rejected for ``text_to_image`` ones."},"num_images":{"type":"integer","maximum":4.0,"minimum":1.0,"title":"Num Images","description":"Number of images to generate in a single call (1 to 4). Each image is billed separately.","default":1},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"Optional integer seed for reproducible output. When set, the same prompt and seed produce consistent results across runs. Leave unset for varied, non-deterministic output."},"param_overrides":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Param Overrides","description":"Per-call parameter overrides merged on top of the generator's default parameters (e.g. image size, aspect ratio). Keys not recognized by the model are passed through as-is."},"version":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Version","description":"Pin to a specific deployed generator version. Defaults to the generator's current version."},"skill_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skill Id","description":"Optional skill UUID for provenance. Access-checked: a skill the caller cannot see surfaces as 404."},"skill_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Skill Version","description":"Skill version invoking this run, paired with ``skill_id``."},"skill_ref":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Skill Ref","description":"Free-form skill label (slug, name) for human-readable provenance."},"run_id":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Run Id","description":"Optional caller-supplied correlation ID stamped onto the run row."},"visibility":{"type":"string","title":"Visibility","description":"Access level for the hosted copy of each generated image. ``public`` (default) returns a link that opens in any browser. ``private`` returns a link only the owner can open and forward, while the plain URL stays locked. Anonymous generations are always public.","default":"public"}},"type":"object","required":["prompt"],"title":"_GenerateImageBody","description":"Request body for ``POST /image-generators/{generator_id}/runs``.\n\nThe ``generator_id`` in the path is the primary generator reference. To\nuse the authenticated one-off model path (a concrete model identifier, no\ndeployed generator), supply ``model`` in the body and use any placeholder\npath segment (e.g. ``-``). ``generator`` and ``model`` are mutually\nexclusive in the underlying call: when ``model`` is set the path id is\nignored.\n\nCaller-shape errors return 400 with no run row written. Provider and\ntimeout errors return 201 with ``status=\"error\"`` and an ``error_code``\nof ``provider_error``, ``runtime_error``, or ``timeout``."},"_GrantSkillIn":{"properties":{"grantee_email_or_at_team_handle":{"type":"string","title":"Grantee Email Or At Team Handle"},"role":{"type":"string","enum":["view","edit","admin"],"title":"Role"},"include_history":{"type":"boolean","title":"Include History","default":false}},"type":"object","required":["grantee_email_or_at_team_handle","role"],"title":"_GrantSkillIn"},"_MePatchIn":{"properties":{"handle":{"type":"string","maxLength":40,"minLength":3,"title":"Handle"}},"type":"object","required":["handle"],"title":"_MePatchIn"},"_PurchaseCreditsIn":{"properties":{"amount_usd":{"type":"integer","title":"Amount Usd","description":"Amount of credits to buy, in whole US dollars."},"idempotency_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency Key","description":"Optional caller-supplied key that makes a retried purchase request safe to resend without buying credits twice."}},"type":"object","required":["amount_usd"],"title":"_PurchaseCreditsIn","description":"Request body for ``POST /billing/credits/purchase``."},"_RevokeSkillGrantIn":{"properties":{"grantee_email_or_at_team_handle":{"type":"string","title":"Grantee Email Or At Team Handle"}},"type":"object","required":["grantee_email_or_at_team_handle"],"title":"_RevokeSkillGrantIn"},"_RunVerifierBody":{"properties":{"version":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Version","description":"Pin to a specific verifier version; defaults to the current version."},"inputs":{"additionalProperties":{"type":"string"},"type":"object","title":"Inputs","description":"Map keyed by the version's ``input_fields``. Keys must match the deployed list exactly; values must be non-empty strings."},"media_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Media Url","description":"Public HTTPS image URL. Required for ``text_image`` and ``image`` contracts, rejected for ``text``."},"skill_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Skill Id","description":"Optional skill UUID for provenance. Access-checked: a skill the caller cannot see surfaces as 404."},"skill_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Skill Version","description":"Skill version invoking this run, paired with ``skill_id``."},"skill_ref":{"anyOf":[{"type":"string","maxLength":256},{"type":"null"}],"title":"Skill Ref","description":"Free-form skill label (slug, name) for human-readable provenance."},"run_id":{"anyOf":[{"type":"string","maxLength":128},{"type":"null"}],"title":"Run Id","description":"Optional caller-supplied correlation ID stamped onto the run row."}},"type":"object","title":"_RunVerifierBody","description":"Request body for ``POST /verifiers/{verifier_id}/runs``.\n\n``inputs`` keys must match the version's ``input_fields`` exactly.\n``media_url`` is required for ``text_image`` and ``image`` contracts, and\nrejected for ``text``. Caller-shape errors return 400 with no run row\nwritten; judge runtime errors return 201 with ``status=\"error\"``."},"_TransferOwnershipIn":{"properties":{"new_owner_user_identifier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Owner User Identifier"},"new_owner_user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Owner User Id"}},"type":"object","title":"_TransferOwnershipIn"},"_TransferSkillOwnershipIn":{"properties":{"new_owner_user_id_or_email":{"type":"string","title":"New Owner User Id Or Email"}},"type":"object","required":["new_owner_user_id_or_email"],"title":"_TransferSkillOwnershipIn"},"_UpdateImageBody":{"properties":{"visibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visibility"},"ttl_seconds":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Ttl Seconds"},"permanent":{"type":"boolean","title":"Permanent","default":false},"rotate_view_secret":{"type":"boolean","title":"Rotate View Secret","default":false}},"type":"object","title":"_UpdateImageBody","description":"Request body for PATCH /images/{image_id}."},"_UpdateSkillFilesIn":{"properties":{"expected_version_token":{"type":"string","format":"uuid","title":"Expected Version Token"},"files":{"items":{"$ref":"#/components/schemas/FilePatchEntry"},"type":"array","title":"Files"},"delete_paths":{"items":{"type":"string"},"type":"array","title":"Delete Paths"},"source":{"anyOf":[{"type":"string","enum":["manual","teach","optimization","description_optimization","audit"]},{"type":"null"}],"title":"Source"}},"type":"object","required":["expected_version_token"],"title":"_UpdateSkillFilesIn","description":"Request body for changing named files in a skill."}}},"servers":[{"url":"/v1"}]}