{
  "openapi": "3.1.0",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "sprintlog Public API",
    "version": "1.0.0",
    "description": "APIキーを発行した組織のプロジェクトと課題を読み取るPublic API v1です。社内限定の課題も対象となり、すべての操作は読み取り専用です。"
  },
  "servers": [
    {
      "url": "https://{your-sprintlog-domain}/api/public/v1",
      "description": "ご利用中のsprintlog環境",
      "variables": {
        "your-sprintlog-domain": {
          "default": "your-sprintlog-domain",
          "description": "契約時に案内されたsprintlogのドメイン"
        }
      }
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Projects",
      "description": "プロジェクトの読み取り"
    },
    {
      "name": "Issues",
      "description": "課題の読み取り"
    }
  ],
  "x-sprintlog-rate-limit": {
    "requests": 60,
    "period": "minute",
    "key": "api-key"
  },
  "x-sprintlog-source-rate-limit": {
    "requests": 300,
    "period": "minute",
    "key": "source-ip"
  },
  "paths": {
    "/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "プロジェクト一覧を取得",
        "description": "APIキーを発行した組織のプロジェクトを取得します。",
        "tags": ["Projects"],
        "x-sprintlog-required-scope": "projects:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectQuery"
          },
          {
            "$ref": "#/components/parameters/ProjectStatus"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "プロジェクト一覧",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/projects/{project}": {
      "get": {
        "operationId": "getProject",
        "summary": "プロジェクト詳細を取得",
        "description": "APIキーを発行した組織に属する指定プロジェクトを取得します。",
        "tags": ["Projects"],
        "x-sprintlog-required-scope": "projects:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectPath"
          }
        ],
        "responses": {
          "200": {
            "description": "プロジェクト詳細",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/issues": {
      "get": {
        "operationId": "listIssues",
        "summary": "課題一覧を取得",
        "description": "APIキーを発行した組織の課題を取得します。社内限定の課題も対象です。",
        "tags": ["Issues"],
        "x-sprintlog-required-scope": "issues:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/IssueQuery"
          },
          {
            "$ref": "#/components/parameters/ProjectKey"
          },
          {
            "$ref": "#/components/parameters/IssueStatus"
          },
          {
            "$ref": "#/components/parameters/IssueType"
          },
          {
            "$ref": "#/components/parameters/IssuePriority"
          },
          {
            "$ref": "#/components/parameters/IssueVisibility"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "課題一覧",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssueListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/issues/{issue}": {
      "get": {
        "operationId": "getIssue",
        "summary": "課題詳細を取得",
        "description": "APIキーを発行した組織に属する指定課題と所属プロジェクトの基本情報を取得します。社内限定の課題も対象です。",
        "tags": ["Issues"],
        "x-sprintlog-required-scope": "issues:read",
        "parameters": [
          {
            "$ref": "#/components/parameters/IssuePath"
          }
        ],
        "responses": {
          "200": {
            "description": "課題詳細",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IssueResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "spl_...",
        "description": "Authorization: Bearer spl_... の形式で指定します。"
      }
    },
    "parameters": {
      "ProjectPath": {
        "name": "project",
        "in": "path",
        "required": true,
        "description": "プロジェクトID",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "IssuePath": {
        "name": "issue",
        "in": "path",
        "required": true,
        "description": "課題ID",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ProjectQuery": {
        "name": "q",
        "in": "query",
        "required": false,
        "description": "プロジェクト名またはキーの検索文字列",
        "schema": {
          "type": "string",
          "maxLength": 200
        }
      },
      "ProjectStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "プロジェクト状態",
        "schema": {
          "type": "string",
          "enum": ["planning", "active", "on_hold", "completed", "archived"]
        }
      },
      "IssueQuery": {
        "name": "q",
        "in": "query",
        "required": false,
        "description": "課題番号またはタイトルの検索文字列",
        "schema": {
          "type": "string",
          "maxLength": 200
        }
      },
      "ProjectKey": {
        "name": "project_key",
        "in": "query",
        "required": false,
        "description": "プロジェクトキー",
        "schema": {
          "type": "string",
          "maxLength": 16
        }
      },
      "IssueStatus": {
        "name": "status",
        "in": "query",
        "required": false,
        "description": "課題状態",
        "schema": {
          "type": "string",
          "maxLength": 30
        }
      },
      "IssueType": {
        "name": "type",
        "in": "query",
        "required": false,
        "description": "課題種別",
        "schema": {
          "type": "string",
          "maxLength": 20
        }
      },
      "IssuePriority": {
        "name": "priority",
        "in": "query",
        "required": false,
        "description": "優先度",
        "schema": {
          "type": "string",
          "enum": ["low", "normal", "high", "urgent"]
        }
      },
      "IssueVisibility": {
        "name": "visibility",
        "in": "query",
        "required": false,
        "description": "公開範囲",
        "schema": {
          "type": "string",
          "enum": ["internal", "client"]
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "required": false,
        "description": "取得ページ",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPage": {
        "name": "per_page",
        "in": "query",
        "required": false,
        "description": "1ページの取得件数",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100
        }
      }
    },
    "schemas": {
      "Project": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "key",
          "name",
          "status",
          "start_date",
          "due_date",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "key": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "start_date": {
            "type": ["string", "null"],
            "format": "date"
          },
          "due_date": {
            "type": ["string", "null"],
            "format": "date"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "IssueProject": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "key", "name"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "key": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "IssueAssignee": {
        "type": "object",
        "additionalProperties": false,
        "required": ["id", "name"],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          }
        }
      },
      "Issue": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "project",
          "number",
          "key",
          "title",
          "type",
          "status",
          "priority",
          "visibility",
          "start_at",
          "due_at",
          "assignee",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project": {
            "$ref": "#/components/schemas/IssueProject"
          },
          "number": {
            "type": "integer",
            "minimum": 1
          },
          "key": {
            "type": "string",
            "description": "プロジェクトキーと課題番号を連結した表示キー"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "priority": {
            "type": "string"
          },
          "visibility": {
            "type": "string",
            "enum": ["internal", "client"]
          },
          "start_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "due_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "assignee": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/IssueAssignee"
              },
              {
                "type": "null"
              }
            ]
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "additionalProperties": false,
        "required": ["current_page", "per_page", "total", "last_page"],
        "properties": {
          "current_page": {
            "type": "integer",
            "minimum": 1
          },
          "per_page": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          },
          "total": {
            "type": "integer",
            "minimum": 0
          },
          "last_page": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "ProjectResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Project"
          }
        }
      },
      "ProjectListResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["data", "meta"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Project"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        }
      },
      "IssueResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["data"],
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Issue"
          }
        }
      },
      "IssueListResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["data", "meta"],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["message"],
        "properties": {
          "message": {
            "type": "string"
          }
        }
      },
      "ValidationErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["message", "errors"],
        "properties": {
          "message": {
            "type": "string"
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "responses": {
      "Unauthenticated": {
        "description": "APIキーがない、無効、または失効しています。",
        "headers": {
          "WWW-Authenticate": {
            "description": "Bearer認証challenge",
            "schema": {
              "type": "string",
              "example": "Bearer realm=\"sprintlog-public-api\""
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Forbidden": {
        "description": "必要なスコープまたはアクセス権がありません。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "対象が存在しないか、参照できる範囲にありません。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ValidationError": {
        "description": "検索条件またはパラメータが正しくありません。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ValidationErrorResponse"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "APIキー毎分60件、または送信元IP毎分300件の上限を超えています。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    }
  }
}
