{
  "openapi": "3.1.0",
  "info": {
    "title": "Screenshare Developer API",
    "version": "1.0.2",
    "description": "Official v1 contract. API keys are server-side only. One organization per key. Ticket content and private notes are excluded. Shared quotas: key 60/min and 5000/day; account and organization 300/min and 20000/day. Invitations: organization 10/min, 60/hour, 200/day including retries. Ticket bridge: organization 60/min; concurrency key 2, organization 4, account 6. See /conventions/ for edge and management protection.",
    "license": {
      "name": "Documentation and example code: see repository"
    }
  },
  "servers": [
    {
      "url": "https://api.screenshare.cn/v1"
    }
  ],
  "security": [
    {
      "ApiKey": []
    }
  ],
  "externalDocs": {
    "url": "https://developer.screenshare.cn"
  },
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Requires a valid API key unless security is explicitly empty.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "status": {
                          "const": "ok"
                        },
                        "version": {
                          "const": "v1"
                        }
                      },
                      "required": [
                        "status",
                        "version"
                      ]
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/me": {
      "get": {
        "operationId": "getIdentity",
        "summary": "Inspect current key and organization",
        "description": "Requires a valid API key unless security is explicitly empty.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Identity"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/entitlements": {
      "get": {
        "operationId": "getPersonalEntitlements",
        "summary": "Read the creator’s personal entitlements",
        "description": "Personal keys only. Organization keys receive 403 PERSONAL_KEY_REQUIRED.",
        "x-required-scopes": [
          "entitlements:read"
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Entitlements"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/records/{uuid}": {
      "get": {
        "operationId": "lookupRecord",
        "summary": "Exact public USS record lookup",
        "description": "Required scope: public:read. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "public:read"
        ],
        "parameters": [
          {
            "name": "uuid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[Uu][Ss][Ss]-[0-9]{8}-[A-Za-z0-9]{12}$"
            },
            "description": "Not a Minecraft account UUID. No result returns 404 RECORD_NOT_FOUND, never clean."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Record"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/records": {
      "get": {
        "operationId": "listOrganizationRecords",
        "summary": "List and synchronize organization records",
        "description": "Required scope: records:read. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "records:read"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque next_cursor from previous page; keep filters unchanged."
          },
          {
            "name": "updated_after",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Inclusive lower bound."
          },
          {
            "name": "result",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "clean",
                "warning",
                "cheating"
              ]
            }
          },
          {
            "name": "game",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "minecraft",
                "fps"
              ]
            }
          },
          {
            "name": "player_name",
            "in": "query",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 120
            },
            "description": "Exact, case-insensitive name."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/RecordPage"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/records/{record_id}": {
      "get": {
        "operationId": "getOrganizationRecord",
        "summary": "Read one organization record",
        "description": "Required scope: records:read. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "records:read"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "record_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Record"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/entitlements": {
      "get": {
        "operationId": "getOrganizationEntitlements",
        "summary": "Read current organization entitlements",
        "description": "Required scope: entitlements:read. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "entitlements:read"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Entitlements"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/invitations": {
      "get": {
        "operationId": "listInvitations",
        "summary": "List organization invitations",
        "description": "Required scope: invitations:read. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "invitations:read"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/InvitationPage"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createInvitation",
        "summary": "Create one-time player invitation",
        "description": "Required scope: invitations:write. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "invitations:write"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{16,128}$"
            },
            "description": "Persist before first call. Reuse the same key, organization, request identifier and normalized JSON on retries."
          }
        ],
        "responses": {
          "200": {
            "description": "Idempotent replay. replayed=true; link may be null if no longer usable.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/InvitationCreated"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "201": {
            "description": "Created a new invitation.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/InvitationCreated"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "game": {
                    "type": "string",
                    "enum": [
                      "minecraft",
                      "fps"
                    ]
                  },
                  "notes": {
                    "type": "string",
                    "maxLength": 600,
                    "description": "Optional; empty or 2–600 characters after trimming."
                  }
                },
                "required": [
                  "game"
                ],
                "additionalProperties": false
              },
              "example": {
                "game": "minecraft",
                "notes": "请配合本次服务器查端。"
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/invitations/{invitation_id}": {
      "get": {
        "operationId": "getInvitation",
        "summary": "Read invitation metadata",
        "description": "Required scope: invitations:read. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "invitations:read"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "invitation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Invitation ID, never the formal ticket ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Invitation"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/invitations/{invitation_id}/link": {
      "get": {
        "operationId": "getInvitationLink",
        "summary": "Recover a pending invitation link",
        "description": "Required scope: invitations:write. Organization operations also require an active actual manager membership and a key bound to partner_id.",
        "x-required-scopes": [
          "invitations:write"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "invitation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Invitation ID, never the formal ticket ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "link": {
                          "type": "string",
                          "format": "uri"
                        }
                      },
                      "required": [
                        "link"
                      ]
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/invitations/{invitation_id}/revoke": {
      "post": {
        "operationId": "revokeInvitation",
        "summary": "Revoke an unused invitation",
        "description": "Only pending invitations can be revoked. Repeating the revocation of an already revoked invitation is idempotent. Joined/claiming tickets cannot be deleted here. No request body.",
        "x-required-scopes": [
          "invitations:write"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "invitation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Invitation ID, never the formal ticket ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Invitation"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/tickets": {
      "get": {
        "operationId": "listTickets",
        "summary": "List joined organization invitations",
        "description": "Joined invitations only, 20 per page. Each item id is the invitation ID; retrieve its current ticket status with getTicket.",
        "x-required-scopes": [
          "tickets:read"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000,
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/InvitationPage"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/partners/{partner_id}/tickets/{invitation_id}": {
      "get": {
        "operationId": "getTicket",
        "summary": "Read ticket progress by invitation ID",
        "description": "Path uses invitation_id, not the formal ticket ID. Returns status and counts only; no body, contact details, remote credentials, attachments or participants. Resolved is not a clean verdict.",
        "x-required-scopes": [
          "tickets:read"
        ],
        "parameters": [
          {
            "name": "partner_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Must exactly match the organization bound to the key."
          },
          {
            "name": "invitation_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Invitation ID, never the formal ticket ID."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful response",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Ticket"
                    },
                    "request_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "ok",
                    "data",
                    "request_id"
                  ]
                }
              }
            }
          },
          "default": {
            "description": "Structured error; use HTTP status and error.code. 429 RATE_LIMITED or CONCURRENCY_LIMITED: pause affected work and obey Retry-After. 503 RATE_LIMIT_UNAVAILABLE: protection unavailable, retry later. Unknown errors must be handled safely.",
            "headers": {
              "X-Request-Id": {
                "schema": {
                  "type": "string"
                }
              },
              "X-RateLimit-Limit": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Maximum requests in the reported quota window, when available."
              },
              "X-RateLimit-Remaining": {
                "schema": {
                  "type": "integer",
                  "minimum": 0
                },
                "description": "Snapshot after admission; concurrent requests can consume it."
              },
              "X-RateLimit-Reset": {
                "schema": {
                  "type": "integer"
                },
                "description": "Window end as Unix seconds. Daily quotas reset at UTC midnight."
              },
              "X-RateLimit-Policy": {
                "schema": {
                  "type": "string"
                },
                "description": "Normally key-minute; a rejection names its limiting policy. Edge/concurrency responses can omit numeric quota headers."
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "minimum": 1
                },
                "description": "Minimum seconds before retry; dynamic, potentially until the next UTC day. Never assume a constant 60 seconds."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "organizationEvent": {
      "post": {
        "operationId": "receiveOrganizationEvent",
        "summary": "Receive a signed organization event",
        "security": [],
        "description": "Verify HMAC-SHA256(full whsec secret, timestamp + dot + raw body), time tolerance, event ID and organization. Persist before 2xx. Delivery is retried and may be duplicated or out of order.",
        "parameters": [
          {
            "name": "X-Screenshare-Event-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Screenshare-Timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]+$"
            }
          },
          {
            "name": "X-Screenshare-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^v1=[a-f0-9]{64}$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Event"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification: echo the exact challenge only after authenticating the request.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "challenge": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "challenge"
                  ]
                }
              }
            }
          },
          "204": {
            "description": "Event durably accepted."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "uss_live_<64 hex>",
        "description": "Created in https://www.screenshare.cn/profile → API & Webhooks. Never expose in browser code."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "const": false
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          },
          "request_id": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "error",
          "request_id"
        ]
      },
      "Record": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "uuid": {
            "type": "string",
            "pattern": "^USS-[0-9]{8}-[A-Z0-9]{12}$"
          },
          "player_name": {
            "type": "string"
          },
          "game_category": {
            "type": "string"
          },
          "game": {
            "type": "string"
          },
          "checked_at": {
            "type": "string",
            "format": "date-time"
          },
          "result": {
            "type": "string",
            "enum": [
              "clean",
              "warning",
              "cheating"
            ]
          },
          "result_label": {
            "type": "string"
          },
          "checker_name": {
            "type": "string"
          },
          "public_notes": {
            "type": "string"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "uuid",
          "player_name",
          "game_category",
          "game",
          "checked_at",
          "result",
          "result_label",
          "checker_name",
          "public_notes",
          "updated_at"
        ]
      },
      "Invitation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "game": {
            "type": "string",
            "enum": [
              "minecraft",
              "fps"
            ]
          },
          "state": {
            "type": "string",
            "enum": [
              "pending",
              "claiming",
              "joined",
              "expired",
              "revoked"
            ]
          },
          "ticket_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "archived_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "game",
          "state",
          "ticket_id",
          "created_at",
          "expires_at",
          "archived_at"
        ]
      },
      "InvitationCreated": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Invitation"
          },
          {
            "type": "object",
            "properties": {
              "link": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri"
              },
              "replayed": {
                "type": "boolean"
              }
            },
            "required": [
              "link",
              "replayed"
            ]
          }
        ]
      },
      "InvitationPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Invitation"
            }
          },
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "page_count": {
            "type": "integer",
            "minimum": 1
          }
        },
        "required": [
          "items",
          "page",
          "page_count"
        ]
      },
      "RecordPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Record"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items",
          "next_cursor"
        ]
      },
      "Ticket": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "invitation_id": {
            "type": "string",
            "format": "uuid"
          },
          "partner_id": {
            "type": "string"
          },
          "game": {
            "type": "string",
            "enum": [
              "minecraft",
              "fps"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "waiting_user",
              "resolved"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "message_count": {
            "type": "integer",
            "minimum": 0
          }
        },
        "required": [
          "id",
          "invitation_id",
          "partner_id",
          "game",
          "status",
          "created_at",
          "updated_at",
          "message_count"
        ]
      },
      "Entitlements": {
        "type": "object",
        "properties": {
          "owner_type": {
            "type": "string",
            "enum": [
              "user",
              "partner"
            ]
          },
          "owner_id": {
            "type": "string"
          },
          "games": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "game": {
                  "type": "string",
                  "enum": [
                    "minecraft",
                    "fps"
                  ]
                },
                "remaining_units": {
                  "type": "integer",
                  "minimum": 0
                },
                "unlimited": {
                  "type": "boolean"
                },
                "total_units": {
                  "type": "integer",
                  "minimum": 0
                },
                "used_units": {
                  "type": "integer",
                  "minimum": 0
                },
                "expires_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                },
                "next_starts_at": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "date-time"
                }
              },
              "required": [
                "game",
                "remaining_units",
                "unlimited",
                "total_units",
                "used_units",
                "expires_at",
                "next_starts_at"
              ]
            }
          }
        },
        "required": [
          "owner_type",
          "owner_id",
          "games"
        ]
      },
      "Identity": {
        "type": "object",
        "properties": {
          "key_id": {
            "type": "string"
          },
          "account_id": {
            "type": "string"
          },
          "partner_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "public:read",
                "records:read",
                "invitations:read",
                "invitations:write",
                "tickets:read",
                "entitlements:read"
              ]
            }
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO 8601 expiration time, or null for a permanent key. Permanent keys remain revocable and subject to account status, organization membership, scopes and rate limits. Does not affect invitation or entitlement expiry."
          }
        },
        "required": [
          "key_id",
          "account_id",
          "partner_id",
          "scopes",
          "expires_at"
        ]
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "record.created",
              "record.updated",
              "record.deleted",
              "invitation.joined",
              "ticket.message.created",
              "ticket.status.updated",
              "entitlement.updated",
              "webhook.verification",
              "webhook.test"
            ]
          },
          "api_version": {
            "const": "v1"
          },
          "partner_id": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object",
            "description": "Resource identifiers only. See /events/ for the exact shape of each event.",
            "additionalProperties": true
          }
        },
        "required": [
          "id",
          "type",
          "api_version",
          "partner_id",
          "created_at",
          "data"
        ]
      }
    }
  }
}
