{ "openapi": "3.1.0", "info": { "title": "FOSSBilling Extensions API (v2)", "version": "2.0.0", "description": "Self-service extension publishing, ownership, moderation, and public browsing. v1 (/extensions/v1) remains available for existing integrations." }, "servers": [ { "url": "/extensions/v2" } ], "components": { "securitySchemes": { "Bearer": { "type": "http", "scheme": "bearer" } }, "schemas": { "UnifiedExtensionListResponse": { "type": "object", "properties": { "result": { "type": "array", "items": { "anyOf": [ { "$ref": "#/components/schemas/ExtensionListItem" }, { "$ref": "#/components/schemas/OwnedExtensionListItem" } ] } }, "pagination": { "$ref": "#/components/schemas/Pagination" } }, "required": ["result", "pagination"] }, "ExtensionListItem": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "type": "string", "minLength": 1, "maxLength": 4000 }, "website": { "type": ["string", "null"], "maxLength": 2048, "format": "uri", "description": "Null when a legacy URL exceeds the card length bound" }, "license": { "$ref": "#/components/schemas/License" }, "icon_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "source": { "$ref": "#/components/schemas/Repository" }, "version": { "type": "string", "minLength": 1, "maxLength": 100 }, "download_url": { "type": ["string", "null"], "maxLength": 2048, "format": "uri", "description": "Null when a legacy URL exceeds the card length bound" }, "id": { "type": "string" }, "developer": { "$ref": "#/components/schemas/PublicDeveloper" } }, "required": [ "type", "name", "description", "website", "license", "source", "version", "download_url", "id", "developer" ] }, "License": { "type": "object", "properties": { "name": { "type": "string", "minLength": 1, "maxLength": 100 }, "spdx_id": { "type": "string", "description": "A current SPDX license identifier (https://spdx.org/licenses/). Omitted for custom or proprietary licenses.", "example": "MIT" }, "URL": { "type": "string", "maxLength": 2048, "format": "uri" } }, "required": ["name"], "additionalProperties": false }, "Repository": { "type": "object", "properties": { "type": { "type": "string", "enum": ["github", "gitlab", "custom"] }, "repo": { "type": "string", "minLength": 1, "maxLength": 500 } }, "required": ["type", "repo"], "additionalProperties": false }, "PublicDeveloper": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }, "type": { "type": "string", "enum": ["user", "organization"] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "URL": { "type": "string", "maxLength": 2048, "format": "uri" }, "avatar_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "approved": { "type": "boolean" }, "unclaimed": { "type": "boolean" } }, "required": ["id", "type", "name", "approved", "unclaimed"] }, "OwnedExtensionListItem": { "type": "object", "properties": { "id": { "type": "string" }, "developer": { "$ref": "#/components/schemas/PublicDeveloper" }, "published": { "type": ["object", "null"], "properties": { "type": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "type": "string", "minLength": 1, "maxLength": 4000 }, "website": { "type": ["string", "null"], "maxLength": 2048, "format": "uri", "description": "Null when a legacy URL exceeds the card length bound" }, "license": { "$ref": "#/components/schemas/License" }, "icon_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "source": { "$ref": "#/components/schemas/Repository" }, "version": { "type": "string", "minLength": 1, "maxLength": 100 }, "download_url": { "type": ["string", "null"], "maxLength": 2048, "format": "uri", "description": "Null when a legacy URL exceeds the card length bound" } }, "required": [ "type", "name", "description", "website", "license", "source", "version", "download_url" ] }, "pending_revision": { "$ref": "#/components/schemas/PendingRevisionRef" }, "last_review": { "$ref": "#/components/schemas/RevisionReview" }, "delisted": { "$ref": "#/components/schemas/DelistedInfo" }, "created_at": { "type": "string" }, "updated_at": { "type": "string" } }, "required": [ "id", "developer", "published", "pending_revision", "last_review", "delisted", "created_at", "updated_at" ] }, "PendingRevisionRef": { "type": ["object", "null"], "properties": { "id": { "type": "string" }, "created_at": { "type": "string" } }, "required": ["id", "created_at"] }, "RevisionReview": { "type": ["object", "null"], "properties": { "revision_id": { "type": "string" }, "status": { "type": "string", "enum": ["approved", "rejected"] }, "review_note": { "type": ["string", "null"] }, "reviewed_at": { "type": ["string", "null"] } }, "required": ["revision_id", "status", "review_note", "reviewed_at"] }, "DelistedInfo": { "type": ["object", "null"], "properties": { "reason": { "type": "string" }, "at": { "type": "string" } }, "required": ["reason", "at"] }, "Pagination": { "type": "object", "properties": { "next_cursor": { "type": ["string", "null"] }, "has_more": { "type": "boolean" } }, "required": ["next_cursor", "has_more"] }, "Error": { "type": "object", "properties": { "error": { "type": "object", "properties": { "message": { "type": "string" }, "code": { "type": "string" }, "details": { "type": "array", "items": { "type": [ "string", "number", "boolean", "object", "array", "null" ] } } }, "required": ["message", "code"] } }, "required": ["error"] }, "ExtensionDetailResponse": { "type": "object", "properties": { "result": { "anyOf": [ { "$ref": "#/components/schemas/Extension" }, { "$ref": "#/components/schemas/OwnedExtension" } ] } }, "required": ["result"] }, "Extension": { "allOf": [ { "$ref": "#/components/schemas/ExtensionContent" }, { "type": "object", "properties": { "id": { "type": "string" }, "developer": { "$ref": "#/components/schemas/PublicDeveloper" } }, "required": ["id", "developer"] } ] }, "Release": { "type": "object", "properties": { "tag": { "type": "string", "minLength": 1, "maxLength": 100 }, "date": { "type": "string", "minLength": 1, "maxLength": 64 }, "download_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "changelog_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "min_fossbilling_version": { "type": "string", "minLength": 1, "maxLength": 100 } }, "required": ["tag", "date", "download_url", "min_fossbilling_version"], "additionalProperties": false }, "ExtensionContent": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "type": "string", "minLength": 1, "maxLength": 4000 }, "releases": { "type": "array", "items": { "$ref": "#/components/schemas/Release" }, "minItems": 1, "maxItems": 100 }, "website": { "type": "string", "maxLength": 2048, "format": "uri" }, "license": { "$ref": "#/components/schemas/License" }, "icon_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "readme": { "type": "string", "minLength": 1, "maxLength": 100000 }, "source": { "$ref": "#/components/schemas/Repository" }, "version": { "type": "string", "minLength": 1, "maxLength": 100 }, "download_url": { "type": "string", "maxLength": 2048, "format": "uri" } }, "required": [ "type", "name", "description", "releases", "website", "license", "readme", "source", "version", "download_url" ] }, "OwnedExtension": { "allOf": [ { "$ref": "#/components/schemas/OwnedExtensionListItem" }, { "type": "object", "properties": { "published": { "allOf": [ { "$ref": "#/components/schemas/ExtensionContent" }, { "type": ["object", "null"], "properties": { "releases": { "type": "array", "items": { "allOf": [ { "$ref": "#/components/schemas/Release" }, { "type": "object", "properties": { "tag": { "type": "string", "minLength": 1, "maxLength": 200, "description": "At most 100 Unicode code points in historical content" } }, "additionalProperties": false } ] }, "maxItems": 100 } } } ] }, "pending_revision": { "allOf": [ { "$ref": "#/components/schemas/PendingRevisionRef" }, { "type": ["object", "null"], "properties": { "content": { "$ref": "#/components/schemas/StoredExtensionContent" } }, "required": ["content"] } ] } } } ] }, "StoredExtensionContent": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "type": "string", "minLength": 1, "maxLength": 4000 }, "releases": { "type": "array", "items": { "allOf": [ { "$ref": "#/components/schemas/Release" }, { "type": "object", "properties": { "tag": { "type": "string", "minLength": 1, "maxLength": 200, "description": "At most 100 Unicode code points in historical content" } }, "additionalProperties": false } ] }, "maxItems": 100 }, "website": { "type": "string", "maxLength": 2048, "format": "uri" }, "license": { "$ref": "#/components/schemas/License" }, "icon_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "readme": { "type": "string", "minLength": 1, "maxLength": 100000 }, "source": { "$ref": "#/components/schemas/Repository" }, "version": { "type": "string", "minLength": 1, "maxLength": 100 }, "download_url": { "type": "string", "maxLength": 2048, "format": "uri" } } }, "ExtensionCreate": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "type": "string", "minLength": 1, "maxLength": 4000 }, "releases": { "type": "array", "items": { "$ref": "#/components/schemas/Release" }, "minItems": 1, "maxItems": 100 }, "website": { "type": "string", "maxLength": 2048, "format": "uri" }, "license": { "$ref": "#/components/schemas/License" }, "icon_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "readme": { "type": "string", "minLength": 1, "maxLength": 100000 }, "source": { "$ref": "#/components/schemas/Repository" }, "version": { "type": "string", "minLength": 1, "maxLength": 100 }, "download_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "id": { "type": "string", "maxLength": 200, "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" } }, "required": [ "type", "name", "description", "releases", "website", "license", "readme", "source", "version", "download_url", "id" ], "additionalProperties": false }, "ExtensionUpdate": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "type": "string", "minLength": 1, "maxLength": 4000 }, "releases": { "type": "array", "items": { "$ref": "#/components/schemas/Release" }, "minItems": 1, "maxItems": 100 }, "website": { "type": "string", "maxLength": 2048, "format": "uri" }, "license": { "$ref": "#/components/schemas/License" }, "icon_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "readme": { "type": "string", "minLength": 1, "maxLength": 100000 }, "source": { "$ref": "#/components/schemas/Repository" }, "version": { "type": "string", "minLength": 1, "maxLength": 100 }, "download_url": { "type": "string", "maxLength": 2048, "format": "uri" } }, "required": [ "type", "name", "description", "releases", "website", "license", "readme", "source", "version", "download_url" ], "additionalProperties": false }, "ExtensionRevisionSummary": { "type": "object", "properties": { "id": { "type": "string" }, "extension_id": { "type": "string" }, "developer_id": { "type": "string" }, "submitted_by": { "type": "string" }, "status": { "type": "string", "enum": ["pending", "approved", "rejected"] }, "name": { "type": ["string", "null"], "maxLength": 120 }, "version": { "type": ["string", "null"], "maxLength": 100 }, "description": { "type": ["string", "null"], "maxLength": 4000 }, "content_bytes": { "type": "integer", "minimum": 0 }, "content_available": { "type": "boolean" }, "content_hash": { "type": ["string", "null"] }, "compacted_at": { "type": ["string", "null"] }, "reviewer_id": { "type": ["string", "null"] }, "review_note": { "type": ["string", "null"] }, "created_at": { "type": "string" }, "reviewed_at": { "type": ["string", "null"] } }, "required": [ "id", "extension_id", "developer_id", "submitted_by", "status", "name", "version", "description", "content_bytes", "content_available", "content_hash", "compacted_at", "reviewer_id", "review_note", "created_at", "reviewed_at" ] }, "ExtensionRevision": { "type": "object", "properties": { "id": { "type": "string" }, "extension_id": { "type": "string" }, "developer_id": { "type": "string" }, "submitted_by": { "type": "string" }, "status": { "type": "string", "enum": ["pending", "approved", "rejected"] }, "content": { "allOf": [ { "$ref": "#/components/schemas/StoredExtensionContent" }, { "type": ["object", "null"] } ] }, "name": { "type": ["string", "null"], "maxLength": 120 }, "version": { "type": ["string", "null"], "maxLength": 100 }, "description": { "type": ["string", "null"], "maxLength": 4000 }, "content_bytes": { "type": "integer", "minimum": 0 }, "content_available": { "type": "boolean" }, "content_hash": { "type": ["string", "null"] }, "compacted_at": { "type": ["string", "null"] }, "reviewer_id": { "type": ["string", "null"] }, "review_note": { "type": ["string", "null"] }, "created_at": { "type": "string" }, "reviewed_at": { "type": ["string", "null"] } }, "required": [ "id", "extension_id", "developer_id", "submitted_by", "status", "content", "name", "version", "description", "content_bytes", "content_available", "content_hash", "compacted_at", "reviewer_id", "review_note", "created_at", "reviewed_at" ] }, "User": { "type": "object", "properties": { "display_name": { "type": ["string", "null"] }, "is_moderator": { "type": "boolean" }, "github_linked": { "type": "boolean" }, "active": { "type": "boolean" } }, "required": ["display_name", "is_moderator", "github_linked", "active"] }, "UserIdentityInput": { "type": "object", "properties": { "name": { "type": ["string", "null"], "maxLength": 200 }, "email": { "type": ["string", "null"], "maxLength": 254, "format": "email" }, "email_verified": { "type": "boolean" }, "picture": { "type": ["string", "null"], "maxLength": 2048 }, "github_login": { "type": ["string", "null"], "maxLength": 200 }, "github_orgs": { "type": ["array", "null"], "items": { "type": "string", "maxLength": 200 }, "maxItems": 500 }, "github_orgs_expires_at": { "type": ["string", "null"], "maxLength": 64 } }, "required": [ "name", "email", "email_verified", "picture", "github_login", "github_orgs", "github_orgs_expires_at" ], "additionalProperties": false }, "UserProfileUpdate": { "type": "object", "properties": { "display_name": { "type": ["string", "null"], "maxLength": 120 } }, "required": ["display_name"], "additionalProperties": false }, "DeveloperClaim": { "type": "object", "properties": { "id": { "type": "string" }, "developer_id": { "type": "string" }, "claimant_id": { "type": "string" }, "status": { "type": "string", "enum": ["pending", "approved", "rejected"] }, "note": { "type": "string" }, "review_note": { "type": "string" }, "reviewer_id": { "type": "string" }, "created_at": { "type": "string" }, "reviewed_at": { "type": "string" }, "github_org_verified": { "type": "boolean" }, "github_verification_note": { "type": "string" } }, "required": [ "id", "developer_id", "claimant_id", "status", "created_at" ] }, "ClaimNote": { "type": "object", "properties": { "note": { "type": "string", "maxLength": 500 } }, "additionalProperties": false }, "PendingDeveloperClaim": { "allOf": [ { "$ref": "#/components/schemas/DeveloperClaim" }, { "type": "object", "properties": { "developer_name": { "type": "string" }, "developer_type": { "type": "string", "enum": ["user", "organization"] }, "claimant_name": { "type": ["string", "null"] }, "claimant_github_login": { "type": ["string", "null"] } }, "required": [ "developer_name", "developer_type", "claimant_name", "claimant_github_login" ] } ] }, "DeveloperProfile": { "allOf": [ { "$ref": "#/components/schemas/Developer" }, { "type": "object", "properties": { "approved": { "type": "boolean" }, "content_revision": { "type": "integer", "exclusiveMinimum": 0 }, "profile_generation": { "type": "string", "pattern": "^[0-9a-f]{32}$" }, "github_org_verified": { "type": "boolean" }, "github_verification_note": { "type": "string" }, "github_verified_at": { "type": ["string", "null"] }, "github_url_verified": { "type": "boolean" }, "unclaimed": { "type": "boolean" }, "owner_name": { "type": ["string", "null"] }, "owner_github_login": { "type": ["string", "null"] } }, "required": ["approved", "content_revision", "profile_generation"] } ] }, "Developer": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }, "type": { "type": "string", "enum": ["user", "organization"] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "URL": { "type": "string", "maxLength": 2048, "format": "uri" }, "avatar_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "contact_email": { "type": "string", "maxLength": 254, "format": "email" } }, "required": ["id", "type", "name"] }, "ReviewNoteRequired": { "type": "object", "properties": { "review_note": { "type": "string", "minLength": 1, "maxLength": 2000 } }, "required": ["review_note"], "additionalProperties": false }, "DeveloperTransfer": { "type": "object", "properties": { "token": { "type": "string" }, "expires_at": { "type": "string" } }, "required": ["token", "expires_at"] }, "TransferAcceptance": { "type": "object", "properties": { "token": { "type": "string", "minLength": 64, "maxLength": 128 } }, "required": ["token"], "additionalProperties": false }, "ReviewNoteOptional": { "type": "object", "properties": { "review_note": { "type": "string", "maxLength": 2000 } }, "additionalProperties": false }, "DelistReason": { "type": "object", "properties": { "reason": { "type": "string", "minLength": 1, "maxLength": 2000 } }, "required": ["reason"], "additionalProperties": false }, "ModeratorCorrect": { "type": "object", "properties": { "type": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "description": { "type": "string", "minLength": 1, "maxLength": 4000 }, "releases": { "type": "array", "items": { "$ref": "#/components/schemas/Release" }, "minItems": 1, "maxItems": 100 }, "website": { "type": "string", "maxLength": 2048, "format": "uri" }, "license": { "$ref": "#/components/schemas/License" }, "icon_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "readme": { "type": "string", "minLength": 1, "maxLength": 100000 }, "source": { "$ref": "#/components/schemas/Repository" }, "version": { "type": "string", "minLength": 1, "maxLength": 100 }, "download_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "correction_note": { "type": "string", "minLength": 1, "maxLength": 2000 } }, "required": [ "type", "name", "description", "releases", "website", "license", "readme", "source", "version", "download_url", "correction_note" ], "additionalProperties": false }, "DeveloperApproval": { "type": "object", "properties": { "expected_revision": { "type": "integer", "exclusiveMinimum": 0 }, "expected_generation": { "type": "string", "pattern": "^[0-9a-f]{32}$" } }, "required": ["expected_revision", "expected_generation"], "additionalProperties": false }, "DeveloperHistoryEntry": { "type": "object", "properties": { "developer_id": { "type": "string" }, "type": { "type": "string", "enum": ["user", "organization"] }, "name": { "type": "string" }, "URL": { "type": "string", "maxLength": 2048, "format": "uri" }, "changed_by": { "type": "string" }, "changed_by_name": { "type": ["string", "null"] }, "changed_at": { "type": "string" } }, "required": [ "developer_id", "type", "name", "changed_by", "changed_by_name", "changed_at" ] }, "OwnedDeveloperProfile": { "anyOf": [ { "allOf": [ { "$ref": "#/components/schemas/DeveloperProfile" }, { "type": "object", "properties": { "has_pending_transfer": { "type": "boolean" } }, "required": ["has_pending_transfer"] } ] }, { "type": "null" } ] }, "DeveloperInput": { "type": "object", "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$" }, "type": { "type": "string", "enum": ["user", "organization"] }, "name": { "type": "string", "minLength": 1, "maxLength": 120 }, "URL": { "type": "string", "maxLength": 2048, "format": "uri" }, "avatar_url": { "type": "string", "maxLength": 2048, "format": "uri" }, "contact_email": { "type": "string", "maxLength": 254, "format": "email" } }, "required": ["id", "type", "name"], "additionalProperties": false }, "DeveloperDetailResponse": { "type": "object", "properties": { "result": { "anyOf": [ { "$ref": "#/components/schemas/PublicDeveloper" }, { "$ref": "#/components/schemas/DeveloperProfile" }, { "$ref": "#/components/schemas/OwnedDeveloperProfile" } ] } }, "required": ["result"] } }, "parameters": {} }, "paths": { "/extensions": { "get": { "tags": ["Extensions"], "summary": "List extensions: published catalogue (scope=public), caller's own (scope=mine), or every extension (scope=all, moderator)", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "enum": [ "mod", "theme", "payment-gateway", "server-manager", "domain-registrar", "hook", "translation" ] }, "required": false, "name": "type", "in": "query" }, { "schema": { "type": "string", "description": "Public scope only" }, "required": false, "description": "Public scope only", "name": "developer_id", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Opaque cursor returned by the previous page" }, "required": false, "description": "Opaque cursor returned by the previous page", "name": "cursor", "in": "query" }, { "schema": { "type": "string", "enum": ["public", "mine", "all"], "default": "public", "description": "public: published catalogue (anonymous allowed). mine: caller's own extensions. all: every extension (moderator only)." }, "required": false, "description": "public: published catalogue (anonymous allowed). mine: caller's own extensions. all: every extension (moderator only).", "name": "scope", "in": "query" }, { "schema": { "type": "string", "enum": ["published", "delisted", "unpublished"], "description": "All scope only: published, delisted, or unpublished" }, "required": false, "description": "All scope only: published, delisted, or unpublished", "name": "status", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 200, "description": "All scope only: case-insensitive substring match on the extension id" }, "required": false, "description": "All scope only: case-insensitive substring match on the extension id", "name": "q", "in": "query" } ], "responses": { "200": { "description": "Extensions matching the scope: catalogue cards for scope=public, owned rows for scope=mine/all", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UnifiedExtensionListResponse" } } } }, "401": { "description": "Invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Inactive account, non-moderator scope=all, or scope misuse", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Filter or pagination query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "tags": ["Extensions"], "summary": "Create an extension and submit its first version for review", "security": [ { "Bearer": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExtensionCreate" } } } }, "responses": { "201": { "description": "Extension created. It holds the id immediately but stays out of the public catalogue until a moderator approves the revision.", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "revision_id": { "type": "string" }, "status": { "type": "string", "enum": ["pending"] } }, "required": ["id", "revision_id", "status"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive, or the caller has no developer profile to publish under", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The id is taken, ownership changed, or the pending-revision limit was reached", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "413": { "description": "Raw request exceeds 512 KiB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Body failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Extension write allowance exhausted; see Retry-After", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Write admission unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}": { "get": { "tags": ["Extensions"], "summary": "Get an extension: published content anonymously, full owned record for its owner or a moderator", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Published projection for anonymous/unrelated callers, owned projection for the owner or a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExtensionDetailResponse" } } } }, "401": { "description": "Invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No extension with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Oversized legacy content requires resubmission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "tags": ["Extensions"], "summary": "Submit an edit to an extension the caller owns", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExtensionUpdate" } } } }, "responses": { "202": { "description": "Edit accepted as a pending revision. The published content is unchanged until a moderator approves it.", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "revision_id": { "type": "string" }, "status": { "type": "string", "enum": ["pending"] } }, "required": ["id", "revision_id", "status"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive, or the caller does not own this extension", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No extension with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "An edit is already awaiting review, or the pending-revision limit was reached", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "413": { "description": "Raw request exceeds 512 KiB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Body failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Extension write allowance exhausted; see Retry-After", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Write admission unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": ["Extensions"], "summary": "Withdraw an extension that has never been published", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Extension and its revisions deleted, and the id released", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "deleted": { "type": "boolean", "enum": [true] } }, "required": ["id", "deleted"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive, or the caller does not own this extension", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No extension with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "The extension is published and cannot be withdrawn", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}/revisions": { "get": { "tags": ["Extensions"], "summary": "List an extension's revisions, newest first", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 1000 }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "Every version proposed for this extension, with its review outcome", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "array", "items": { "$ref": "#/components/schemas/ExtensionRevisionSummary" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } }, "required": ["result", "pagination"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive, or the caller neither owns this extension nor moderates", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No extension with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Pagination query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}/revisions/{revisionId}": { "get": { "tags": ["Extensions"], "summary": "Read one revision; compacted content is null", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "acme-gateway" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "revisionId", "in": "path" } ], "responses": { "200": { "description": "One revision with its review outcome; content is null when compacted", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/ExtensionRevision" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive, or the caller neither owns this extension nor moderates", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No extension or revision with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Oversized legacy content requires administrative export or resubmission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Path failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/me/identity": { "put": { "tags": ["Users"], "summary": "Synchronize the caller's OIDC identity projection", "security": [ { "Bearer": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserIdentityInput" } } } }, "responses": { "200": { "description": "Identity projection synchronized", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/User" } }, "required": ["result"] } } } }, "400": { "description": "Request body could not be read", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Identity synchronization requires a trusted assertion", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Identity payload failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/users/me": { "get": { "tags": ["Users"], "summary": "Get the caller's account projection", "security": [ { "Bearer": [] } ], "responses": { "200": { "description": "The caller's account projection, including active status", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/User" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Account does not exist", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "patch": { "tags": ["Users"], "summary": "Update the caller's personal profile", "security": [ { "Bearer": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserProfileUpdate" } } } }, "responses": { "200": { "description": "Profile updated (full account projection)", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/User" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The bearer is valid but the account is inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Account does not exist or has been deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": ["Users"], "summary": "Delete the caller's account and tombstone its user row", "security": [ { "Bearer": [] } ], "responses": { "200": { "description": "Account deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "deleted": { "type": "boolean", "enum": [true] } }, "required": ["deleted"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Account does not exist", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Account still owns protected domain records", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/{id}/claim": { "post": { "tags": ["Developers"], "summary": "Request ownership of an unowned developer profile", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClaimNote" } } } }, "responses": { "201": { "description": "Claim created and pending moderator review", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/DeveloperClaim" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive, or the caller's linked GitHub account doesn't match this developer's GitHub organization or username", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No developer with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Profile is already owned, caller already owns a different profile, or already has a pending claim on this one", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "The request failed validation, or the GitHub account type is unsupported", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Claim allowance exhausted or GitHub verification is temporarily rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "GitHub verification is temporarily unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/claims/{id}/cancel": { "post": { "tags": ["Developers"], "summary": "Withdraw the caller's own pending profile claim", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Claim withdrawn", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "cancelled": { "type": "boolean", "enum": [true] } }, "required": ["id", "cancelled"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The bearer is valid but the account is inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No pending claim with that id owned by the caller", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/claims": { "get": { "tags": ["Developers"], "summary": "List claims: caller's own (?scope=mine) or pending review (?scope=pending, moderator)", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Opaque cursor returned by the previous page" }, "required": false, "description": "Opaque cursor returned by the previous page", "name": "cursor", "in": "query" }, { "schema": { "type": "string", "enum": ["mine", "pending"], "description": "mine: the caller's own claims. pending: claims awaiting review (moderator only)." }, "required": true, "description": "mine: the caller's own claims. pending: claims awaiting review (moderator only).", "name": "scope", "in": "query" }, { "schema": { "type": "string", "enum": ["pending", "approved", "rejected", "all"], "default": "all", "description": "Filter claims by status (default: all). With scope=mine, narrows claims; with scope=pending, only all or pending is allowed." }, "required": false, "description": "Filter claims by status (default: all). With scope=mine, narrows claims; with scope=pending, only all or pending is allowed.", "name": "status", "in": "query" } ], "responses": { "200": { "description": "Enriched claims with developer and claimant names in both scopes", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "array", "items": { "$ref": "#/components/schemas/PendingDeveloperClaim" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } }, "required": ["result", "pagination"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The bearer is valid but the account is inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "scope, status, limit, or cursor query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/claims/{id}/approve": { "post": { "tags": ["Developers"], "summary": "Approve a pending profile claim", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": ["true", "false"], "description": "Set to false to skip the author notification email for this action" }, "required": false, "description": "Set to false to skip the author notification email for this action", "name": "notify", "in": "query" } ], "responses": { "200": { "description": "Claim approved; profile ownership transferred to the claimant", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "allOf": [ { "$ref": "#/components/schemas/DeveloperProfile" }, { "type": "object", "properties": { "notified": { "type": "boolean", "description": "Whether a notification email was dispatched - delivery itself is asynchronous", "example": true } }, "required": ["notified"] } ] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No claim or developer with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Claim is no longer pending, profile is no longer unowned, or the claimant now owns a different profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param or notify query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/claims/{id}/reject": { "post": { "tags": ["Developers"], "summary": "Reject a pending profile claim", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": ["true", "false"], "description": "Set to false to skip the author notification email for this action" }, "required": false, "description": "Set to false to skip the author notification email for this action", "name": "notify", "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewNoteRequired" } } } }, "responses": { "200": { "description": "Claim rejected", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "allOf": [ { "$ref": "#/components/schemas/DeveloperClaim" }, { "type": "object", "properties": { "notified": { "type": "boolean", "description": "Whether a notification email was dispatched - delivery itself is asynchronous", "example": true } }, "required": ["notified"] } ] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No pending claim with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param, review_note body, or notify query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/{id}/transfer": { "post": { "tags": ["Developers"], "summary": "Create a single-use link to hand this profile to another account", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Transfer token created; share it out-of-band with the recipient", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/DeveloperTransfer" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller does not own this profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No developer with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Ownership conflict", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/{id}/transfer/revoke": { "post": { "tags": ["Developers"], "summary": "Revoke this profile's pending transfer link, if any", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Any pending transfer for this profile is revoked", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "revoked": { "type": "boolean", "enum": [true] } }, "required": ["id", "revoked"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller does not own this profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No developer with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Ownership conflict", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/transfers/accept": { "post": { "tags": ["Developers"], "summary": "Accept a developer profile transfer using its single-use token", "security": [ { "Bearer": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TransferAcceptance" } } } }, "responses": { "200": { "description": "Profile is now owned by the caller", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/DeveloperProfile" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The bearer is valid but the account is inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Transfer link is invalid, already used, or expired", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Caller already owns a different developer profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "token body failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}/revisions/{revisionId}/approve": { "post": { "tags": ["Moderation"], "summary": "Approve a pending revision and publish it", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "acme-gateway" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "revisionId", "in": "path" }, { "schema": { "type": "string", "enum": ["true", "false"], "description": "Set to false to skip the author notification email for this action" }, "required": false, "description": "Set to false to skip the author notification email for this action", "name": "notify", "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewNoteOptional" } } } }, "responses": { "200": { "description": "Revision approved and published as the extension's live content", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "enum": ["approved"] }, "notified": { "type": "boolean", "description": "Whether a notification email was dispatched - delivery itself is asynchronous", "example": true } }, "required": ["id", "status", "notified"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such revision on that extension", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Revision is not pending, or ownership has changed since it was proposed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Path params, review_note body, or notify query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}/revisions/{revisionId}/reject": { "post": { "tags": ["Moderation"], "summary": "Reject a pending revision", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "acme-gateway" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "revisionId", "in": "path" }, { "schema": { "type": "string", "enum": ["true", "false"], "description": "Set to false to skip the author notification email for this action" }, "required": false, "description": "Set to false to skip the author notification email for this action", "name": "notify", "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewNoteRequired" } } } }, "responses": { "200": { "description": "Revision rejected. The extension's published content is unchanged.", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "enum": ["rejected"] }, "notified": { "type": "boolean", "description": "Whether a notification email was dispatched - delivery itself is asynchronous", "example": true } }, "required": ["id", "status", "notified"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such revision on that extension", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Revision is not pending", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "review_note body or notify query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}/delist": { "post": { "tags": ["Moderation"], "summary": "Remove a published extension from the public catalogue", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": ["true", "false"], "description": "Set to false to skip the author notification email for this action" }, "required": false, "description": "Set to false to skip the author notification email for this action", "name": "notify", "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DelistReason" } } } }, "responses": { "200": { "description": "Extension removed from the public catalogue. Its content and history are kept, and its owner can still see and edit it.", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "enum": ["delisted"] }, "notified": { "type": "boolean", "description": "Whether a notification email was dispatched - delivery itself is asynchronous", "example": true } }, "required": ["id", "status", "notified"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such extension", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Extension is not published, or is already delisted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Path params, reason body, or notify query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}/relist": { "post": { "tags": ["Moderation"], "summary": "Restore a delisted extension to the public catalogue", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": ["true", "false"], "description": "Set to false to skip the author notification email for this action" }, "required": false, "description": "Set to false to skip the author notification email for this action", "name": "notify", "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReviewNoteOptional" } } } }, "responses": { "200": { "description": "Extension restored to the public catalogue. Content and history unchanged.", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "status": { "type": "string", "enum": ["relisted"] }, "notified": { "type": "boolean", "description": "Whether a notification email was dispatched - delivery itself is asynchronous", "example": true } }, "required": ["id", "status", "notified"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such extension", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Extension is not delisted, or was never published", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Path params, review_note body, or notify query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/extensions/{id}/moderator-correct": { "post": { "tags": ["Moderation"], "summary": "Correct a published extension's live content as a moderator", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModeratorCorrect" } } } }, "responses": { "200": { "description": "Content corrected and published. Recorded as an approved moderator revision; no author email is sent.", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "revision_id": { "type": "string" }, "status": { "type": "string", "enum": ["approved"] } }, "required": ["id", "revision_id", "status"] } }, "required": ["result"] } } } }, "400": { "description": "Unable to read request body", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No such extension", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Extension is unpublished or delisted, or an edit is already awaiting review", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "413": { "description": "Raw request exceeds 512 KiB", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Path params, content, or correction_note failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "Extension write allowance exhausted; see Retry-After", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "Write admission unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/{id}/approve": { "post": { "tags": ["Moderation"], "summary": "Mark a developer profile as reviewed/approved", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "string", "enum": ["true", "false"], "description": "Set to false to skip the author notification email for this action" }, "required": false, "description": "Set to false to skip the author notification email for this action", "name": "notify", "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeveloperApproval" } } } }, "responses": { "200": { "description": "Developer profile marked approved", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "approved": { "type": "boolean", "enum": [true] }, "notified": { "type": "boolean", "description": "Whether a notification email was dispatched - delivery itself is asynchronous", "example": true } }, "required": ["id", "approved", "notified"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No developer with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Profile changed after the reviewed revision", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param, approval body, or notify query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/{id}/history": { "get": { "tags": ["Moderation"], "summary": "List the write history of a developer profile", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Opaque cursor returned by the previous page" }, "required": false, "description": "Opaque cursor returned by the previous page", "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "Snapshots of the profile, newest first", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "array", "items": { "$ref": "#/components/schemas/DeveloperHistoryEntry" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } }, "required": ["result", "pagination"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param, limit, or cursor query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/moderation/counts": { "get": { "tags": ["Moderation"], "summary": "Queue totals for the admin tabs", "security": [ { "Bearer": [] } ], "responses": { "200": { "description": "Pending/decided totals per queue", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "revisions": { "type": "object", "properties": { "pending": { "type": "number" }, "approved": { "type": "number" }, "rejected": { "type": "number" } }, "required": ["pending", "approved", "rejected"] }, "extensions": { "type": "object", "properties": { "all": { "type": "number" }, "published": { "type": "number" }, "delisted": { "type": "number" }, "unpublished": { "type": "number" } }, "required": [ "all", "published", "delisted", "unpublished" ] } }, "required": ["revisions", "extensions"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/revisions": { "get": { "tags": ["Moderation"], "summary": "List extension revisions by status, oldest first", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "enum": ["pending", "approved", "rejected"] }, "required": false, "name": "status", "in": "query" }, { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 1000 }, "required": false, "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "Revisions matching the requested status (default: pending), oldest first", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "array", "items": { "$ref": "#/components/schemas/ExtensionRevisionSummary" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } }, "required": ["result", "pagination"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Status, limit, or cursor query param failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers": { "get": { "tags": ["Developers"], "summary": "List developer profiles: every profile (scope=all) or awaiting review (scope=unapproved)", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 }, "required": false, "name": "limit", "in": "query" }, { "schema": { "type": "string", "minLength": 1, "maxLength": 1000, "description": "Opaque cursor returned by the previous page" }, "required": false, "description": "Opaque cursor returned by the previous page", "name": "cursor", "in": "query" }, { "schema": { "type": "string", "enum": ["all", "unapproved"], "description": "all: every profile (default). unapproved: only profiles awaiting review." }, "required": false, "description": "all: every profile (default). unapproved: only profiles awaiting review.", "name": "scope", "in": "query" }, { "schema": { "type": "string", "enum": ["all", "unapproved"], "description": "Deprecated alias for scope." }, "required": false, "description": "Deprecated alias for scope.", "name": "status", "in": "query", "deprecated": true } ], "responses": { "200": { "description": "Developer profiles matching the scope filter", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "array", "items": { "$ref": "#/components/schemas/DeveloperProfile" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } }, "required": ["result", "pagination"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive or the caller is not a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "scope, status, limit, or cursor query failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/me": { "get": { "tags": ["Developers"], "summary": "Get the caller's own developer profile", "security": [ { "Bearer": [] } ], "responses": { "200": { "description": "The caller's profile, or null when none exists", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/OwnedDeveloperProfile" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The bearer is valid but the account is inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "tags": ["Developers"], "summary": "Create or update the caller's own developer profile", "security": [ { "Bearer": [] } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeveloperInput" } } } }, "responses": { "200": { "description": "Developer profile created or updated and usable immediately", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/DeveloperProfile" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The account is inactive, or this id matches a real GitHub organization or username that isn't linked to the caller's account", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Developer id already taken by someone else, or id was changed on an existing profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "Payload failed validation, or the GitHub account type is unsupported", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "The account exhausted its profile creation or daily write allowance, or GitHub verification is temporarily rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "GitHub verification is temporarily unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": ["Developers"], "summary": "Permanently delete the caller's own developer profile", "security": [ { "Bearer": [] } ], "responses": { "200": { "description": "Profile deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "type": "object", "properties": { "id": { "type": "string" }, "deleted": { "type": "boolean", "enum": [true] } }, "required": ["id", "deleted"] } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The bearer is valid but the account is inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Caller has no developer profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Profile still has extensions attached, published or not", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/me/reverify": { "post": { "tags": ["Developers"], "summary": "Re-check the caller's linked GitHub identity against their own developer profile", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "enum": ["true", "false"] }, "required": false, "name": "check_url", "in": "query" } ], "responses": { "200": { "description": "Verification re-checked (result may be verified or not)", "content": { "application/json": { "schema": { "type": "object", "properties": { "result": { "$ref": "#/components/schemas/DeveloperProfile" } }, "required": ["result"] } } } }, "401": { "description": "Missing or invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "The bearer is valid but the account is inactive", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Caller has no developer profile", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "409": { "description": "Developer ownership changed while re-verifying", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "The GitHub account type is unsupported", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "429": { "description": "check_url was used again too soon, or GitHub verification is rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "503": { "description": "GitHub verification is temporarily unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/developers/{id}": { "get": { "tags": ["Developers"], "summary": "Get a developer profile: public view anonymously, full view for the owner or a moderator", "security": [ { "Bearer": [] } ], "parameters": [ { "schema": { "type": "string", "example": "b6e2c9c4-3f1a-4e9b-9c3a-2e4b1a2f9d10" }, "required": true, "name": "id", "in": "path" } ], "responses": { "200": { "description": "Public profile for anonymous callers, owned/full profile for the owner or a moderator", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DeveloperDetailResponse" } } } }, "401": { "description": "Invalid bearer token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "No developer with that id", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "422": { "description": "id param failed validation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "500": { "description": "Database error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } } }, "webhooks": {} }