{ "openapi": "3.0.0", "paths": { "/api/health": { "get": { "operationId": "HealthController_check", "parameters": [], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "example": { "status": "ok", "postgres": "up", "mongo": "up", "redis": "up" } } } } }, "503": { "description": "A database is down" } }, "summary": "API and databases status", "tags": [ "Health" ], "security": [] } }, "/api/auth/config": { "get": { "operationId": "AuthController_config", "parameters": [], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthorizationConfigDto" } } } } }, "summary": "How to sign in with Pireon (null when not configured)", "tags": [ "Auth" ], "security": [] } }, "/api/auth/token": { "post": { "description": "For browsers (Pireon has no CORS) and Swagger UI: adds the client secret server-side. Apps with their own Pireon OAuth client can get tokens from Pireon directly; any valid Pireon access token is accepted by this API.", "operationId": "AuthController_token", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssueTokenDto" } }, "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/IssueTokenDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TokenResponseDto" } } } }, "401": { "description": "Pireon rejected the grant" } }, "summary": "Exchange a grant for Pireon tokens (proxy of Pireon /oauth/token)", "tags": [ "Auth" ], "security": [] } }, "/api/users/me": { "get": { "operationId": "UsersController_me", "parameters": [], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MeDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "The user behind the access token", "tags": [ "Users" ] } }, "/api/users": { "get": { "description": "Needs the `users:read` scope in the access token.", "operationId": "UsersController_search", "parameters": [ { "name": "search", "required": false, "in": "query", "description": "Name or email", "schema": { "default": "", "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 100, "default": 20, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/UserDto" } } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Search Pireon users (to assign tickets or add members)", "tags": [ "Users" ] } }, "/api/users/{id}": { "get": { "operationId": "UsersController_findOne", "parameters": [ { "name": "id", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "A Pireon user", "tags": [ "Users" ] } }, "/api/webhooks/pireon": { "post": { "description": "`user.deactivated` closes the user's sessions; `token.revoked` forgets the token. Disabled unless PIREON_WEBHOOK_SECRET is set.", "operationId": "PireonWebhookController_receive", "parameters": [ { "name": "x-webhook-signature", "required": true, "in": "header", "schema": { "type": "string" } }, { "name": "X-Webhook-Signature", "in": "header", "description": "HMAC-SHA256 of the raw body with PIREON_WEBHOOK_SECRET (hex)", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Processed" }, "401": { "description": "Missing or invalid signature" } }, "summary": "Pireon events (called by Pireon, not by apps)", "tags": [ "Webhooks" ], "security": [] } }, "/api/projects": { "get": { "operationId": "ProjectsController_mine", "parameters": [], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ProjectDto" } } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Projects where I am a member", "tags": [ "Projects" ] }, "post": { "operationId": "ProjectsController_create", "parameters": [], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateProjectDto" } } } }, "responses": { "201": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Create a project (you become its owner)", "tags": [ "Projects" ] } }, "/api/projects/{project}": { "get": { "operationId": "ProjectsController_findOne", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "A project with its members and settings", "tags": [ "Projects" ] }, "patch": { "operationId": "ProjectsController_update", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateProjectDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Rename, describe or make public/private a project (owner/admin)", "tags": [ "Projects" ] }, "delete": { "description": "Deletes the project and, right after (asynchronously, through a saga), its tickets, comments and releases; links from tickets of other projects are removed and the key becomes free. Cannot be undone from the API. `confirm` must be the project key.", "operationId": "ProjectsController_remove", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } }, { "name": "confirm", "required": true, "in": "query", "description": "The project key, to confirm the deletion", "schema": { "example": "WEB", "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Delete a project (owner only)", "tags": [ "Projects" ] } }, "/api/projects/{project}/settings": { "put": { "description": "Replaces the whole configuration (send what GET /projects/{project} returns, changed). Values can be added, renamed, reordered or archived, never removed: tickets and statistics keep referring to them.", "operationId": "ProjectsController_updateSettings", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectSettingsBodyDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Statuses, transitions, ticket types and areas (owner/admin)", "tags": [ "Projects" ] } }, "/api/projects/{project}/board": { "get": { "operationId": "ProjectsController_board", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } }, { "name": "releaseId", "required": false, "in": "query", "description": "Only this release", "schema": { "format": "uuid", "type": "string" } }, { "name": "assigneeId", "required": false, "in": "query", "description": "Only this person (Pireon user id)", "schema": { "type": "string" } }, { "name": "area", "required": false, "in": "query", "description": "An area id", "schema": { "example": "FRONTEND", "type": "string" } }, { "name": "perColumn", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 200, "default": 50, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/BoardColumnDto" } } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Kanban board: one column per status", "tags": [ "Projects" ] } }, "/api/projects/{project}/stats": { "get": { "operationId": "ProjectsController_stats", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectStatsDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Tracking dashboard: counts by status, type, person…", "tags": [ "Projects" ] } }, "/api/projects/{project}/analytics": { "get": { "description": "Created vs resolved per week, cumulative flow per day, cycle and lead time, throughput per person and QA pass/fail.", "operationId": "ProjectsController_analytics", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } }, { "name": "days", "required": false, "in": "query", "schema": { "minimum": 7, "maximum": 365, "default": 90, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProjectAnalyticsDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Statistics of the last `days` days", "tags": [ "Projects" ] } }, "/api/projects/{project}/activity": { "get": { "operationId": "ProjectsController_activity", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } }, { "name": "issueId", "required": false, "in": "query", "description": "Only this ticket", "schema": { "format": "uuid", "type": "string" } }, { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 200, "default": 50, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "before", "required": false, "in": "query", "description": "Cursor: entries older than this date", "schema": { "format": "date-time", "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ActivityDto" } } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Activity feed (newest first)", "tags": [ "Projects" ] } }, "/api/projects/{project}/members": { "post": { "description": "The user must exist and be active in Pireon.", "operationId": "ProjectsController_addMember", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddMemberDto" } } } }, "responses": { "201": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Add a Pireon user to the project (owner/admin)", "tags": [ "Projects" ] } }, "/api/projects/{project}/members/{userId}": { "patch": { "operationId": "ProjectsController_changeMemberRole", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } }, { "name": "userId", "required": true, "in": "path", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeMemberRoleDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Change a member's role (owner/admin)", "tags": [ "Projects" ] }, "delete": { "operationId": "ProjectsController_removeMember", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } }, { "name": "userId", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Remove a member (owner/admin, or yourself to leave)", "tags": [ "Projects" ] } }, "/api/me/issues": { "get": { "description": "Assigned to me by default; with assignedToMe=false, any ticket of my projects (e.g. waiting for QA).", "operationId": "IssuesController_mine", "parameters": [ { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 200, "default": 50, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "offset", "required": false, "in": "query", "schema": { "minimum": 0, "default": 0, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "assignedToMe", "required": false, "in": "query", "description": "true: tickets assigned to me. false: any ticket of my projects (e.g. ?assignedToMe=false&category=QA)", "schema": { "default": true, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "status", "required": false, "in": "query", "description": "Status ids. Repeat the parameter or separate with commas", "schema": { "type": "array", "items": { "type": "string" } } }, { "name": "category", "required": false, "in": "query", "description": "Whatever each project calls its statuses", "schema": { "type": "array", "items": { "$ref": "#/components/schemas/StatusCategory" } } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssuePageDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "My work: tickets across all my projects", "tags": [ "Issues" ] } }, "/api/projects/{project}/issues": { "get": { "operationId": "IssuesController_search", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } }, { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 200, "default": 50, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "offset", "required": false, "in": "query", "schema": { "minimum": 0, "default": 0, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "status", "required": false, "in": "query", "description": "Status ids. Repeat the parameter or separate with commas", "schema": { "type": "array", "items": { "type": "string" } } }, { "name": "category", "required": false, "in": "query", "schema": { "type": "array", "items": { "$ref": "#/components/schemas/StatusCategory" } } }, { "name": "type", "required": false, "in": "query", "description": "Ticket type ids", "schema": { "type": "array", "items": { "type": "string" } } }, { "name": "area", "required": false, "in": "query", "description": "Area ids", "schema": { "type": "array", "items": { "type": "string" } } }, { "name": "priority", "required": false, "in": "query", "schema": { "type": "array", "items": { "$ref": "#/components/schemas/IssuePriority" } } }, { "name": "assigneeId", "required": false, "in": "query", "description": "Pireon user id", "schema": { "type": "string" } }, { "name": "unassigned", "required": false, "in": "query", "description": "Only tickets without assignee", "schema": { "type": "boolean" } }, { "name": "releaseId", "required": false, "in": "query", "schema": { "format": "uuid", "type": "string" } }, { "name": "label", "required": false, "in": "query", "schema": { "type": "array", "items": { "type": "string" } } }, { "name": "search", "required": false, "in": "query", "description": "Matches key, title or description", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssuePageDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Search the tickets of a project", "tags": [ "Issues" ] }, "post": { "description": "Starts in the project's first active TODO-category status (BACKLOG by default). The response carries its key (e.g. WEB-13).", "operationId": "IssuesController_create", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateIssueDto" } } } }, "responses": { "201": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Create a ticket", "tags": [ "Issues" ] } }, "/api/issues/{issue}": { "get": { "operationId": "IssuesController_findOne", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssueDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "A ticket", "tags": [ "Issues" ] }, "patch": { "operationId": "IssuesController_update", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateIssueDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Edit title, description, type, priority, area, labels…", "tags": [ "Issues" ] } }, "/api/issues/{issue}/status": { "put": { "description": "Only the transitions in `allowedTransitions` are accepted (422 otherwise). QA_FAILED and CANCELLED need a reason.", "operationId": "IssuesController_changeStatus", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChangeStatusDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Move the ticket through the workflow (incl. QA)", "tags": [ "Issues" ] } }, "/api/issues/{issue}/assignee": { "put": { "operationId": "IssuesController_assign", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AssignIssueDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Assign to a project member (null to unassign)", "tags": [ "Issues" ] } }, "/api/issues/{issue}/release": { "put": { "operationId": "IssuesController_setRelease", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetIssueReleaseDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Put the ticket in a planned release (null takes it out)", "tags": [ "Issues" ] } }, "/api/issues/{issue}/links": { "post": { "description": "e.g. WEB-3 DEPENDS_ON API-7, WEB-9 TESTS WEB-3. May cross projects.", "operationId": "IssuesController_link", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LinkIssueDto" } } } }, "responses": { "201": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Relate tickets (FE ↔ BE ↔ QA)", "tags": [ "Issues" ] } }, "/api/issues/{issue}/links/{type}/{target}": { "delete": { "operationId": "IssuesController_unlink", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } }, { "name": "type", "required": true, "in": "path", "schema": { "$ref": "#/components/schemas/IssueLinkType" } }, { "name": "target", "required": true, "in": "path", "description": "Other ticket: id or key", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Remove a relation", "tags": [ "Issues" ] } }, "/api/issues/{issue}/comments": { "get": { "operationId": "IssuesController_listComments", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } }, { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 200, "default": 50, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "offset", "required": false, "in": "query", "schema": { "minimum": 0, "default": 0, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommentPageDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Comments of the ticket (oldest first)", "tags": [ "Issues" ] }, "post": { "operationId": "IssuesController_addComment", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommentBodyDto" } } } }, "responses": { "201": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Comment on the ticket", "tags": [ "Issues" ] } }, "/api/issues/{issue}/history": { "get": { "operationId": "IssuesController_history", "parameters": [ { "name": "issue", "required": true, "in": "path", "description": "Ticket id or key", "schema": { "example": "WEB-12", "type": "string" } }, { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 200, "default": 50, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "offset", "required": false, "in": "query", "schema": { "minimum": 0, "default": 0, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ActivityDto" } } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "History of the ticket (newest first)", "tags": [ "Issues" ] } }, "/api/comments/{commentId}": { "patch": { "operationId": "CommentsController_edit", "parameters": [ { "name": "commentId", "required": true, "in": "path", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommentBodyDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Edit a comment (author only)", "tags": [ "Comments" ] }, "delete": { "operationId": "CommentsController_delete", "parameters": [ { "name": "commentId", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Delete a comment (author or project admin)", "tags": [ "Comments" ] } }, "/api/me/releases": { "get": { "operationId": "ReleasesController_upcoming", "parameters": [ { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 50, "default": 10, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ReleaseDto" } } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Planned releases of all my projects, soonest target date first", "tags": [ "Releases" ] } }, "/api/projects/{project}/releases": { "get": { "operationId": "ReleasesController_list", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ReleaseDto" } } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Releases of a project", "tags": [ "Releases" ] }, "post": { "operationId": "ReleasesController_create", "parameters": [ { "name": "project", "required": true, "in": "path", "description": "Project id or key", "schema": { "example": "WEB", "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateReleaseDto" } } } }, "responses": { "201": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Plan a release (owner/admin)", "tags": [ "Releases" ] } }, "/api/releases/{releaseId}": { "get": { "operationId": "ReleasesController_findOne", "parameters": [ { "name": "releaseId", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReleaseDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "A release", "tags": [ "Releases" ] }, "patch": { "operationId": "ReleasesController_update", "parameters": [ { "name": "releaseId", "required": true, "in": "path", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateReleaseDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Rename, describe or move the target date", "tags": [ "Releases" ] } }, "/api/releases/{releaseId}/progress": { "get": { "operationId": "ReleasesController_progress", "parameters": [ { "name": "releaseId", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReleaseProgressDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Finished tickets out of the total", "tags": [ "Releases" ] } }, "/api/releases/{releaseId}/burnup": { "get": { "operationId": "ReleasesController_burnup", "parameters": [ { "name": "releaseId", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReleaseBurnupDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Burnup: tickets in the release and finished ones, day by day", "tags": [ "Releases" ] } }, "/api/releases/{releaseId}/issues": { "get": { "operationId": "ReleasesController_issuesOf", "parameters": [ { "name": "releaseId", "required": true, "in": "path", "schema": { "type": "string" } }, { "name": "limit", "required": false, "in": "query", "schema": { "minimum": 1, "maximum": 200, "default": 50, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } }, { "name": "offset", "required": false, "in": "query", "schema": { "minimum": 0, "default": 0, "allOf": [ { "$ref": "#/components/schemas/Object" } ] } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IssuePageDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] }, {} ], "summary": "Tickets included in the release", "tags": [ "Releases" ] } }, "/api/releases/{releaseId}/publish": { "post": { "description": "Fails (422) while it has unfinished tickets unless `force` is true.", "operationId": "ReleasesController_publish", "parameters": [ { "name": "releaseId", "required": true, "in": "path", "schema": { "type": "string" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublishReleaseDto" } } } }, "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Ship the release", "tags": [ "Releases" ] } }, "/api/releases/{releaseId}/archive": { "post": { "operationId": "ReleasesController_archive", "parameters": [ { "name": "releaseId", "required": true, "in": "path", "schema": { "type": "string" } } ], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CommandResultDto" } } } }, "400": { "description": "Invalid input", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "401": { "description": "Missing or rejected Pireon token", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "403": { "description": "Not a member of the project (or not allowed)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "404": { "description": "Not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "409": { "description": "Someone changed it at the same time: retry", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } }, "422": { "description": "Business rule (e.g. a transition the workflow forbids)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiErrorDto" } } } } }, "security": [ { "pireon-oauth": [] }, { "pireon": [] } ], "summary": "Archive a planned release (its tickets leave it)", "tags": [ "Releases" ] } }, "/api/explore/projects": { "get": { "description": "Their board, tickets, comments, releases, activity and statistics can be read without a token too.", "operationId": "ExploreController_publicProjects", "parameters": [], "responses": { "200": { "description": "", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/ProjectDto" } } } } } }, "summary": "Public projects (no token needed)", "tags": [ "Explore" ], "security": [] } } }, "info": { "title": "Pireon TaskStream API", "description": "REST API of **Pireon TaskStream** for other apps: projects, tickets (bugs, features,\nUI changes, tasks and QA), workflow, comments, relations and releases.\n\n### Authentication\nEvery endpoint (except `/auth`, `/health` and the webhook) needs a **Pireon access\ntoken**, so any app or user that consumes it goes through Pireon's OAuth:\n\n- **Authorization Code + PKCE** against `oauth.pireon.dev/oauth/authorize`\n (the \"Authorize\" button here uses it; register `/api/docs/oauth2-redirect.html`\n as a redirect URI of the client).\n- An app with its own Pireon OAuth client can get tokens from Pireon directly and\n send them as `Authorization: Bearer `.\n\nWhat you can see and change depends on your role in each project.\n\n### Writes are eventually consistent\nCommands answer `{ id, key?, version }` as soon as the event is stored. Reads come from\na read model that catches up in milliseconds: a `GET` right after a write may still\nshow the previous version (or 404 right after a create).\n\n### Real time\nFor live updates use the GraphQL subscriptions at `/graphql` (graphql-ws).", "version": "1.0.0", "contact": {} }, "tags": [ { "name": "Projects", "description": "Projects, members, board, stats and activity" }, { "name": "Issues", "description": "Tickets: search, create, workflow, relations, comments" }, { "name": "Comments", "description": "Edit and delete comments" }, { "name": "Releases", "description": "Versions that group tickets" }, { "name": "Users", "description": "The signed-in user and the Pireon directory" }, { "name": "Auth", "description": "Pireon OAuth token proxy" }, { "name": "Health", "description": "Liveness of the API and its databases" }, { "name": "Webhooks", "description": "Called by Pireon" } ], "servers": [ { "url": "/", "description": "This server (the paths already include /api)" } ], "components": { "securitySchemes": { "pireon-oauth": { "type": "oauth2", "flows": { "authorizationCode": { "authorizationUrl": "https://oauth.pireon.dev/oauth/authorize", "tokenUrl": "/api/auth/token", "refreshUrl": "/api/auth/token", "scopes": { "users:read": "Search Pireon users" } }, "password": { "tokenUrl": "/api/auth/token", "refreshUrl": "/api/auth/token", "scopes": { "users:read": "Search Pireon users" } } }, "description": "Pireon OAuth2 (Laravel Passport)" }, "pireon": { "scheme": "bearer", "bearerFormat": "JWT", "type": "http", "description": "A Pireon access token obtained elsewhere" } }, "schemas": { "AuthorizationConfigDto": { "type": "object", "properties": { "authorizeUrl": { "type": "string", "example": "https://oauth.pireon.dev/oauth/authorize" }, "clientId": { "type": "string", "nullable": true, "description": "Public id of the authorization_code client (\"Sign in with Pireon\"); null when only email + password is configured" }, "scopes": { "example": [ "users:read" ], "type": "array", "items": { "type": "string" } }, "passwordGrant": { "type": "boolean", "description": "Whether email + password sign-in is allowed" } }, "required": [ "authorizeUrl", "clientId", "scopes", "passwordGrant" ] }, "IssueTokenDto": { "type": "object", "properties": { "grant_type": { "type": "string", "enum": [ "authorization_code", "password", "refresh_token" ] }, "code": { "type": "string", "description": "authorization_code: code returned by Pireon" }, "code_verifier": { "type": "string", "description": "authorization_code: PKCE verifier" }, "redirect_uri": { "type": "string", "description": "authorization_code: redirect URI used to authorize" }, "username": { "type": "string", "description": "password: Pireon email" }, "password": { "type": "string", "description": "password: Pireon password" }, "refresh_token": { "type": "string", "description": "refresh_token" } }, "required": [ "grant_type" ] }, "TokenResponseDto": { "type": "object", "properties": { "access_token": { "type": "string" }, "refresh_token": { "type": "string", "nullable": true }, "expires_in": { "type": "number", "description": "Seconds" }, "token_type": { "type": "string", "example": "Bearer" } }, "required": [ "access_token", "refresh_token", "expires_in", "token_type" ] }, "MeDto": { "type": "object", "properties": { "id": { "type": "string", "description": "Pireon user id" }, "name": { "type": "string" }, "email": { "type": "string" }, "isActive": { "type": "boolean" }, "roles": { "description": "Global roles in Pireon", "type": "array", "items": { "type": "string" } }, "appRoles": { "description": "Roles inside the task-stream OAuth client", "type": "array", "items": { "type": "string" } } }, "required": [ "id", "name", "email", "isActive", "roles", "appRoles" ] }, "ApiErrorDto": { "type": "object", "properties": { "statusCode": { "type": "number", "example": 404 }, "code": { "type": "string", "description": "Domain error code", "enum": [ "NOT_FOUND", "FORBIDDEN", "VALIDATION", "CONFLICT", "BUSINESS_RULE" ] }, "message": { "description": "Human message (a list of messages for invalid input)", "oneOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ], "example": "Issue not found" } }, "required": [ "statusCode", "message" ] }, "Object": { "type": "object", "properties": {} }, "UserDto": { "type": "object", "properties": { "id": { "type": "string", "description": "Pireon user id" }, "name": { "type": "string" }, "email": { "type": "string" }, "isActive": { "type": "boolean" } }, "required": [ "id", "name", "email", "isActive" ] }, "UserRefDto": { "type": "object", "properties": { "id": { "type": "string", "description": "Pireon user id" }, "name": { "type": "string" } }, "required": [ "id", "name" ] }, "ProjectRole": { "type": "string", "enum": [ "OWNER", "ADMIN", "MEMBER", "VIEWER" ] }, "ProjectMemberDto": { "type": "object", "properties": { "user": { "$ref": "#/components/schemas/UserRefDto" }, "role": { "allOf": [ { "$ref": "#/components/schemas/ProjectRole" } ] } }, "required": [ "user", "role" ] }, "StatusCategory": { "type": "string", "enum": [ "TODO", "IN_PROGRESS", "QA", "DONE", "CANCELLED" ] }, "SettingColor": { "type": "string", "enum": [ "slate", "stone", "violet", "blue", "sky", "teal", "green", "amber", "orange", "red", "pink" ] }, "WorkflowStatusDto": { "type": "object", "properties": { "id": { "type": "string", "example": "IN_REVIEW", "description": "Stable id on tickets" }, "name": { "type": "string", "example": "En revisión" }, "category": { "allOf": [ { "$ref": "#/components/schemas/StatusCategory" } ] }, "color": { "allOf": [ { "$ref": "#/components/schemas/SettingColor" } ] }, "requiresReason": { "type": "boolean", "description": "Entering it needs a reason" }, "archived": { "type": "boolean", "description": "No new tickets or transitions into it" } }, "required": [ "id", "name", "category", "color", "requiresReason", "archived" ] }, "StatusTransitionsDto": { "type": "object", "properties": { "from": { "type": "string", "example": "IN_QA" }, "to": { "example": [ "DONE", "QA_FAILED" ], "type": "array", "items": { "type": "string" } } }, "required": [ "from", "to" ] }, "TypeIcon": { "type": "string", "enum": [ "bug", "feature", "palette", "task", "qa", "flag", "star-fill", "rocket", "document", "light-bulb", "key", "support" ] }, "IssueTypeOptionDto": { "type": "object", "properties": { "id": { "type": "string", "example": "BUG" }, "name": { "type": "string", "example": "Bug" }, "icon": { "allOf": [ { "$ref": "#/components/schemas/TypeIcon" } ] }, "color": { "allOf": [ { "$ref": "#/components/schemas/SettingColor" } ] }, "archived": { "type": "boolean" } }, "required": [ "id", "name", "icon", "color", "archived" ] }, "AreaOptionDto": { "type": "object", "properties": { "id": { "type": "string", "example": "FRONTEND" }, "name": { "type": "string", "example": "Frontend" }, "archived": { "type": "boolean" } }, "required": [ "id", "name", "archived" ] }, "ProjectSettingsDto": { "type": "object", "properties": { "statuses": { "description": "In board order", "type": "array", "items": { "$ref": "#/components/schemas/WorkflowStatusDto" } }, "transitions": { "type": "array", "items": { "$ref": "#/components/schemas/StatusTransitionsDto" } }, "issueTypes": { "type": "array", "items": { "$ref": "#/components/schemas/IssueTypeOptionDto" } }, "areas": { "type": "array", "items": { "$ref": "#/components/schemas/AreaOptionDto" } } }, "required": [ "statuses", "transitions", "issueTypes", "areas" ] }, "ProjectDto": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "key": { "type": "string", "example": "WEB", "description": "Prefix of the ticket keys" }, "name": { "type": "string", "example": "Checkout revamp" }, "description": { "type": "string", "nullable": true }, "isPublic": { "type": "boolean", "description": "Readable by anyone, also without a token" }, "owner": { "$ref": "#/components/schemas/UserRefDto" }, "members": { "type": "array", "items": { "$ref": "#/components/schemas/ProjectMemberDto" } }, "settings": { "$ref": "#/components/schemas/ProjectSettingsDto" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "version": { "type": "number", "description": "Version of the aggregate (event count)" } }, "required": [ "id", "key", "name", "description", "isPublic", "owner", "members", "settings", "createdAt", "updatedAt", "version" ] }, "CreateProjectDto": { "type": "object", "properties": { "key": { "type": "string", "example": "WEB", "description": "2-10 letters/digits starting with a letter → tickets WEB-1, WEB-2…" }, "name": { "type": "string", "example": "Checkout revamp", "maxLength": 120 }, "description": { "type": "string", "nullable": true, "maxLength": 5000 }, "isPublic": { "type": "boolean", "default": false, "description": "Anyone can read it without signing in (board, tickets, comments, releases, activity, statistics)" } }, "required": [ "key", "name" ] }, "CommandResultDto": { "type": "object", "properties": { "id": { "type": "string", "description": "Id of the aggregate written" }, "key": { "type": "string", "description": "Human key when one was assigned (project or issue)", "example": "WEB-13" }, "version": { "type": "number", "description": "Version after the write. Writes are acknowledged at once and the read model catches up asynchronously: a GET may briefly return the previous version (or 404 right after a create)." } }, "required": [ "id", "version" ] }, "UpdateProjectDto": { "type": "object", "properties": { "name": { "type": "string", "example": "Checkout revamp", "maxLength": 120 }, "description": { "type": "string", "nullable": true, "maxLength": 5000 }, "isPublic": { "type": "boolean", "default": false, "description": "Anyone can read it without signing in (board, tickets, comments, releases, activity, statistics)" } } }, "WorkflowStatusBodyDto": { "type": "object", "properties": { "id": { "type": "string", "example": "IN_REVIEW", "description": "Never change an existing id" }, "name": { "type": "string", "example": "En revisión", "maxLength": 40 }, "category": { "allOf": [ { "$ref": "#/components/schemas/StatusCategory" } ] }, "color": { "allOf": [ { "$ref": "#/components/schemas/SettingColor" } ] }, "requiresReason": { "type": "object", "default": false }, "archived": { "type": "object", "default": false } }, "required": [ "id", "name", "category", "color" ] }, "StatusTransitionsBodyDto": { "type": "object", "properties": { "from": { "type": "string", "example": "IN_QA" }, "to": { "example": [ "DONE", "QA_FAILED" ], "type": "array", "items": { "type": "string" } } }, "required": [ "from", "to" ] }, "IssueTypeOptionBodyDto": { "type": "object", "properties": { "id": { "type": "string", "example": "SPIKE" }, "name": { "type": "string", "example": "Spike", "maxLength": 40 }, "icon": { "allOf": [ { "$ref": "#/components/schemas/TypeIcon" } ] }, "color": { "allOf": [ { "$ref": "#/components/schemas/SettingColor" } ] }, "archived": { "type": "object", "default": false } }, "required": [ "id", "name", "icon", "color" ] }, "AreaOptionBodyDto": { "type": "object", "properties": { "id": { "type": "string", "example": "DATA" }, "name": { "type": "string", "example": "Datos", "maxLength": 40 }, "archived": { "type": "object", "default": false } }, "required": [ "id", "name" ] }, "ProjectSettingsBodyDto": { "type": "object", "properties": { "statuses": { "description": "In board order. Values cannot be removed: archive them instead.", "type": "array", "items": { "$ref": "#/components/schemas/WorkflowStatusBodyDto" } }, "transitions": { "type": "array", "items": { "$ref": "#/components/schemas/StatusTransitionsBodyDto" } }, "issueTypes": { "type": "array", "items": { "$ref": "#/components/schemas/IssueTypeOptionBodyDto" } }, "areas": { "type": "array", "items": { "$ref": "#/components/schemas/AreaOptionBodyDto" } } }, "required": [ "statuses", "transitions", "issueTypes", "areas" ] }, "IssuePriority": { "type": "string", "enum": [ "LOWEST", "LOW", "MEDIUM", "HIGH", "CRITICAL" ] }, "ReleaseRefDto": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "name": { "type": "string", "example": "v1.4.0" } }, "required": [ "id", "name" ] }, "IssueLinkType": { "type": "string", "enum": [ "BLOCKS", "DEPENDS_ON", "TESTS", "DUPLICATES", "RELATES_TO" ] }, "LinkDirection": { "type": "string", "enum": [ "OUTWARD", "INWARD" ], "description": "OUTWARD: this issue → other. INWARD: other → this issue." }, "IssueLinkDto": { "type": "object", "properties": { "type": { "allOf": [ { "$ref": "#/components/schemas/IssueLinkType" } ] }, "direction": { "description": "OUTWARD: this issue → other. INWARD: other → this issue.", "allOf": [ { "$ref": "#/components/schemas/LinkDirection" } ] }, "issueId": { "type": "string", "format": "uuid" }, "issueKey": { "type": "string", "example": "WEB-3" } }, "required": [ "type", "direction", "issueId", "issueKey" ] }, "IssueDto": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "projectId": { "type": "string", "format": "uuid" }, "projectKey": { "type": "string", "example": "WEB" }, "number": { "type": "number", "example": 12 }, "key": { "type": "string", "example": "WEB-12", "description": "Human key" }, "type": { "type": "string", "example": "BUG", "description": "A ticket type id" }, "area": { "type": "string", "nullable": true, "example": "FRONTEND" }, "title": { "type": "string" }, "description": { "type": "string", "nullable": true }, "status": { "type": "string", "example": "IN_PROGRESS", "description": "A status id" }, "statusCategory": { "allOf": [ { "$ref": "#/components/schemas/StatusCategory" } ] }, "allowedTransitions": { "description": "Statuses this ticket can move to next (project's workflow)", "type": "array", "items": { "type": "string" } }, "priority": { "allOf": [ { "$ref": "#/components/schemas/IssuePriority" } ] }, "reporter": { "$ref": "#/components/schemas/UserRefDto" }, "assignee": { "nullable": true, "type": "object", "allOf": [ { "$ref": "#/components/schemas/UserRefDto" } ] }, "release": { "nullable": true, "type": "object", "allOf": [ { "$ref": "#/components/schemas/ReleaseRefDto" } ] }, "labels": { "type": "array", "items": { "type": "string" } }, "figmaUrl": { "type": "string", "nullable": true, "description": "Figma frame" }, "storyPoints": { "type": "number", "nullable": true }, "dueDate": { "type": "string", "nullable": true, "format": "date" }, "links": { "type": "array", "items": { "$ref": "#/components/schemas/IssueLinkDto" } }, "commentCount": { "type": "number" }, "createdAt": { "type": "string", "format": "date-time" }, "updatedAt": { "type": "string", "format": "date-time" }, "version": { "type": "number" } }, "required": [ "id", "projectId", "projectKey", "number", "key", "type", "area", "title", "description", "status", "statusCategory", "allowedTransitions", "priority", "reporter", "assignee", "release", "labels", "figmaUrl", "storyPoints", "dueDate", "links", "commentCount", "createdAt", "updatedAt", "version" ] }, "BoardColumnDto": { "type": "object", "properties": { "status": { "type": "string", "example": "IN_PROGRESS" }, "issues": { "type": "array", "items": { "$ref": "#/components/schemas/IssueDto" } }, "total": { "type": "number", "description": "Tickets in the column (may exceed `issues`)" } }, "required": [ "status", "issues", "total" ] }, "CountByStatusDto": { "type": "object", "properties": { "key": { "type": "string", "example": "IN_PROGRESS", "description": "Status id" }, "count": { "type": "number" } }, "required": [ "key", "count" ] }, "CountByKeyDto": { "type": "object", "properties": { "key": { "type": "string", "description": "Type, priority or area (\"NONE\" = unset)" }, "count": { "type": "number" } }, "required": [ "key", "count" ] }, "CountByAssigneeDto": { "type": "object", "properties": { "user": { "nullable": true, "description": "Null = unassigned", "type": "object", "allOf": [ { "$ref": "#/components/schemas/UserRefDto" } ] }, "count": { "type": "number" } }, "required": [ "user", "count" ] }, "ProjectStatsDto": { "type": "object", "properties": { "total": { "type": "number" }, "open": { "type": "number", "description": "Not done nor cancelled" }, "byStatus": { "type": "array", "items": { "$ref": "#/components/schemas/CountByStatusDto" } }, "byType": { "type": "array", "items": { "$ref": "#/components/schemas/CountByKeyDto" } }, "byPriority": { "type": "array", "items": { "$ref": "#/components/schemas/CountByKeyDto" } }, "byArea": { "type": "array", "items": { "$ref": "#/components/schemas/CountByKeyDto" } }, "byAssignee": { "description": "Open tickets per person", "type": "array", "items": { "$ref": "#/components/schemas/CountByAssigneeDto" } } }, "required": [ "total", "open", "byStatus", "byType", "byPriority", "byArea", "byAssignee" ] }, "CreatedResolvedDto": { "type": "object", "properties": { "week": { "type": "string", "format": "date", "description": "Monday of the week" }, "created": { "type": "number" }, "resolved": { "type": "number" } }, "required": [ "week", "created", "resolved" ] }, "FlowSeriesDto": { "type": "object", "properties": { "status": { "type": "string", "example": "IN_PROGRESS" }, "counts": { "description": "One value per date", "type": "array", "items": { "type": "number" } } }, "required": [ "status", "counts" ] }, "CumulativeFlowDto": { "type": "object", "properties": { "dates": { "type": "array", "items": { "type": "string", "format": "date" } }, "series": { "type": "array", "items": { "$ref": "#/components/schemas/FlowSeriesDto" } } }, "required": [ "dates", "series" ] }, "DurationStatsDto": { "type": "object", "properties": { "count": { "type": "number" }, "averageDays": { "type": "number", "nullable": true }, "p85Days": { "type": "number", "nullable": true, "description": "85% of tickets take at most this long" } }, "required": [ "count", "averageDays", "p85Days" ] }, "ThroughputDto": { "type": "object", "properties": { "week": { "type": "string", "format": "date" }, "user": { "nullable": true, "type": "object", "allOf": [ { "$ref": "#/components/schemas/UserRefDto" } ] }, "count": { "type": "number" } }, "required": [ "week", "user", "count" ] }, "QaStatsDto": { "type": "object", "properties": { "passed": { "type": "number", "description": "Left QA to a done status" }, "failed": { "type": "number", "description": "Left QA back to work" }, "failureRate": { "type": "number", "nullable": true, "minimum": 0, "maximum": 1 } }, "required": [ "passed", "failed", "failureRate" ] }, "ProjectAnalyticsDto": { "type": "object", "properties": { "from": { "type": "string", "format": "date-time" }, "to": { "type": "string", "format": "date-time" }, "createdVsResolved": { "type": "array", "items": { "$ref": "#/components/schemas/CreatedResolvedDto" } }, "cumulativeFlow": { "description": "Tickets in each status at the end of every day", "allOf": [ { "$ref": "#/components/schemas/CumulativeFlowDto" } ] }, "cycleTime": { "description": "Start of work → done", "allOf": [ { "$ref": "#/components/schemas/DurationStatsDto" } ] }, "leadTime": { "description": "Creation → done", "allOf": [ { "$ref": "#/components/schemas/DurationStatsDto" } ] }, "throughput": { "type": "array", "items": { "$ref": "#/components/schemas/ThroughputDto" } }, "qa": { "$ref": "#/components/schemas/QaStatsDto" } }, "required": [ "from", "to", "createdVsResolved", "cumulativeFlow", "cycleTime", "leadTime", "throughput", "qa" ] }, "ActivityDto": { "type": "object", "properties": { "id": { "type": "string" }, "type": { "type": "string", "example": "IssueStatusChanged" }, "projectId": { "type": "string", "format": "uuid" }, "issueId": { "type": "string", "nullable": true }, "issueKey": { "type": "string", "nullable": true, "example": "WEB-12" }, "actor": { "$ref": "#/components/schemas/UserRefDto" }, "summary": { "type": "string", "example": "Ana movió WEB-12 de En curso a En revisión" }, "occurredAt": { "type": "string", "format": "date-time" } }, "required": [ "id", "type", "projectId", "issueId", "issueKey", "actor", "summary", "occurredAt" ] }, "AddMemberDto": { "type": "object", "properties": { "userId": { "type": "string", "description": "Pireon user id (see GET /users)" }, "role": { "default": "MEMBER", "allOf": [ { "$ref": "#/components/schemas/ProjectRole" } ] } }, "required": [ "userId" ] }, "ChangeMemberRoleDto": { "type": "object", "properties": { "role": { "allOf": [ { "$ref": "#/components/schemas/ProjectRole" } ] } }, "required": [ "role" ] }, "IssuePageDto": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/IssueDto" } }, "total": { "type": "number", "description": "Total matches (for pagination)" } }, "required": [ "items", "total" ] }, "CreateIssueDto": { "type": "object", "properties": { "description": { "type": "string", "nullable": true, "maxLength": 50000 }, "area": { "type": "string", "nullable": true, "example": "FRONTEND", "description": "An area id of the project's settings" }, "priority": { "allOf": [ { "$ref": "#/components/schemas/IssuePriority" } ] }, "labels": { "maxItems": 20, "type": "array", "items": { "type": "string" } }, "figmaUrl": { "type": "string", "nullable": true, "description": "Figma frame (https) for UI changes" }, "storyPoints": { "type": "number", "nullable": true, "minimum": 0, "maximum": 100 }, "dueDate": { "type": "string", "nullable": true, "format": "date" }, "type": { "type": "string", "example": "BUG", "description": "A ticket type id of the project's settings" }, "title": { "type": "string", "example": "El botón de pagar no responde en Safari", "maxLength": 255 }, "assigneeId": { "type": "string", "nullable": true, "description": "Pireon user id" }, "releaseId": { "type": "string", "nullable": true, "format": "uuid" } }, "required": [ "type", "title" ] }, "UpdateIssueDto": { "type": "object", "properties": { "description": { "type": "string", "nullable": true, "maxLength": 50000 }, "area": { "type": "string", "nullable": true, "example": "FRONTEND", "description": "An area id of the project's settings" }, "priority": { "allOf": [ { "$ref": "#/components/schemas/IssuePriority" } ] }, "labels": { "maxItems": 20, "type": "array", "items": { "type": "string" } }, "figmaUrl": { "type": "string", "nullable": true, "description": "Figma frame (https) for UI changes" }, "storyPoints": { "type": "number", "nullable": true, "minimum": 0, "maximum": 100 }, "dueDate": { "type": "string", "nullable": true, "format": "date" }, "type": { "type": "string", "example": "FEATURE", "description": "A ticket type id" }, "title": { "type": "string", "maxLength": 255 } } }, "ChangeStatusDto": { "type": "object", "properties": { "status": { "type": "string", "example": "IN_REVIEW", "description": "A status id of the project's settings, among the ticket's allowedTransitions" }, "reason": { "type": "string", "nullable": true, "description": "Required by statuses with requiresReason (e.g. QA_FAILED)" } }, "required": [ "status" ] }, "AssignIssueDto": { "type": "object", "properties": { "assigneeId": { "type": "string", "nullable": true, "description": "Pireon user id of a project member, or null to unassign" } }, "required": [ "assigneeId" ] }, "SetIssueReleaseDto": { "type": "object", "properties": { "releaseId": { "type": "string", "nullable": true, "format": "uuid", "description": "Planned release, or null to take the ticket out" } }, "required": [ "releaseId" ] }, "LinkIssueDto": { "type": "object", "properties": { "type": { "allOf": [ { "$ref": "#/components/schemas/IssueLinkType" } ] }, "targetIssue": { "type": "string", "example": "API-3", "description": "Other ticket: id or key" } }, "required": [ "type", "targetIssue" ] }, "CommentDto": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "issueId": { "type": "string", "format": "uuid" }, "author": { "$ref": "#/components/schemas/UserRefDto" }, "body": { "type": "string" }, "createdAt": { "type": "string", "format": "date-time" }, "editedAt": { "type": "string", "nullable": true, "format": "date-time" }, "version": { "type": "number" } }, "required": [ "id", "issueId", "author", "body", "createdAt", "editedAt", "version" ] }, "CommentPageDto": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/CommentDto" } }, "total": { "type": "number" } }, "required": [ "items", "total" ] }, "CommentBodyDto": { "type": "object", "properties": { "body": { "type": "string", "example": "Reproducido en Safari 17.", "maxLength": 20000 } }, "required": [ "body" ] }, "ReleaseStatus": { "type": "string", "enum": [ "PLANNED", "RELEASED", "ARCHIVED" ] }, "ReleaseDto": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "projectId": { "type": "string", "format": "uuid" }, "name": { "type": "string", "example": "v1.4.0" }, "description": { "type": "string", "nullable": true }, "targetDate": { "type": "string", "nullable": true, "format": "date" }, "status": { "allOf": [ { "$ref": "#/components/schemas/ReleaseStatus" } ] }, "releasedAt": { "type": "string", "nullable": true, "format": "date-time" }, "createdAt": { "type": "string", "format": "date-time" }, "version": { "type": "number" } }, "required": [ "id", "projectId", "name", "description", "targetDate", "status", "releasedAt", "createdAt", "version" ] }, "CreateReleaseDto": { "type": "object", "properties": { "name": { "type": "string", "example": "v1.4.0", "maxLength": 60 }, "description": { "type": "string", "nullable": true, "maxLength": 5000 }, "targetDate": { "type": "string", "nullable": true, "format": "date", "example": "2026-11-14" } }, "required": [ "name" ] }, "UpdateReleaseDto": { "type": "object", "properties": { "name": { "type": "string", "example": "v1.4.0", "maxLength": 60 }, "description": { "type": "string", "nullable": true, "maxLength": 5000 }, "targetDate": { "type": "string", "nullable": true, "format": "date", "example": "2026-11-14" } } }, "ReleaseProgressDto": { "type": "object", "properties": { "total": { "type": "number" }, "finished": { "type": "number" }, "percent": { "type": "number", "minimum": 0, "maximum": 100 }, "byStatus": { "type": "array", "items": { "$ref": "#/components/schemas/CountByStatusDto" } } }, "required": [ "total", "finished", "percent", "byStatus" ] }, "ReleaseBurnupDto": { "type": "object", "properties": { "releaseId": { "type": "string", "format": "uuid" }, "targetDate": { "type": "string", "nullable": true, "format": "date" }, "dates": { "type": "array", "items": { "type": "string", "format": "date" } }, "scope": { "description": "Tickets in the release (not cancelled)", "type": "array", "items": { "type": "number" } }, "done": { "type": "array", "items": { "type": "number" } } }, "required": [ "releaseId", "targetDate", "dates", "scope", "done" ] }, "PublishReleaseDto": { "type": "object", "properties": { "force": { "type": "object", "default": false, "description": "Publish even with unfinished tickets" } } } } } }