# ------------------------------------------------------ # THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) # ------------------------------------------------------ type Activity { actor: UserRef! id: ID! issueId: ID issueKey: String occurredAt: String! projectId: ID! summary: String! type: String! } """How much happened on one day""" type ActivityDay { count: Int! """YYYY-MM-DD""" day: String! } input AddChecklistItemInput { issueId: ID! text: String! } """Something on a day of my week""" type AgendaItem { """YYYY-MM-DD""" day: String! issueKey: String """ISSUE, SPRINT_END or RELEASE""" kind: String! projectKey: String! title: String! } type Aging { issues: [InsightIssue!]! """p85 cycle time of the last 90 days""" thresholdDays: Float } """Alerts → bugs: the secret URL monitoring tools call to open bugs""" type AlertIntegration { enabled: Boolean! priority: IssuePriority! """Ticket type it opens; null: the project's first bug type""" typeId: ID """ Path of the URL on this API, secret token included; only owners and admins see it """ webhookPath: String } input AlertSettingsInput { priority: IssuePriority """Ticket type to open; null: the project's first bug type""" typeId: ID } type AreaOption { archived: Boolean! id: String! name: String! } input AreaOptionInput { archived: Boolean! = false id: String! name: String! } """ A file on a ticket. Download it from the REST API: GET /api/issues/{issueId}/attachments/{id} """ type Attachment { """The comment it was attached to, if any""" commentId: ID fileName: String! id: ID! mimeType: String! """Bytes""" size: Int! uploadedAt: String! uploadedBy: UserRef! } """When this happens to a ticket, if it is like this, do that""" type Automation { action: AutomationActionSpec! active: Boolean! conditions: AutomationConditions! createdAt: String! createdBy: UserRef! id: ID! """Why the last run did nothing""" lastError: String lastRunAt: String name: String! projectId: ID! runs: Int! trigger: AutomationTriggerSpec! } """What a rule does to the ticket""" enum AutomationAction { ADD_COMMENT ADD_LABEL ADD_TO_ACTIVE_SPRINT ASSIGN ASSIGN_REPORTER SET_PRIORITY SET_STATUS } input AutomationActionInput { kind: AutomationAction! value: String } type AutomationActionSpec { kind: AutomationAction! """Status, member id, label, priority or comment text""" value: String } type AutomationConditions { areas: [String!] label: String priorities: [IssuePriority!] types: [String!] } input AutomationConditionsInput { areas: [String!] label: String priorities: [IssuePriority!] types: [String!] } """What starts a rule""" enum AutomationTrigger { COMMENT_ADDED ISSUE_ASSIGNED ISSUE_CREATED PULL_REQUEST_MERGED STATUS_CHANGED } input AutomationTriggerInput { kind: AutomationTrigger! status: String } type AutomationTriggerSpec { kind: AutomationTrigger! """STATUS_CHANGED: only into this status""" status: String } type BacklogHealth { noArea: Int! open: Int! stale: Int! staleDays: Int! unassigned: Int! unestimated: Int! } type BoardColumn { issues: [Issue!]! status: String! total: Int! } """Bugs created and closed in a week""" type BugWeek { closed: Int! created: Int! """Monday (UTC), YYYY-MM-DD""" week: String! } type BulkIssueResult { error: String issueId: ID! ok: Boolean! } type BulkResult { results: [BulkIssueResult!]! updated: Int! } input BulkUpdateIssuesInput { addLabels: [String!] assigneeId: ID issueIds: [ID!]! """Out of their release""" noRelease: Boolean """Back to the backlog""" noSprint: Boolean priority: IssuePriority releaseId: ID sprintId: ID status: String """Unassign everything""" unassign: Boolean } type CalendarFeed { createdAt: String! """ Secret of the calendar URL: GET /api/calendar/{token}.ics (iCalendar, no session) """ token: String! } input ChangeIssueStatusInput { issueId: ID! """Required by statuses with requiresReason""" reason: String """A status id""" status: String! } """What happened after a moment""" type ChangesSince { created: [InsightIssue!]! createdCount: Int! finished: [InsightIssue!]! finishedCount: Int! """Times I was mentioned here""" mentions: Int! """Sent back from QA""" returned: [InsightIssue!]! returnedCount: Int! since: String! } """A step inside a ticket that does not deserve a ticket of its own""" type ChecklistItem { done: Boolean! id: ID! text: String! } """How far the tickets hanging from one have got""" type ChildProgress { """Done or cancelled""" finished: Int! finishedStoryPoints: Int! percent: Int! storyPoints: Int! total: Int! } """ Writes are acknowledged immediately; the read model catches up asynchronously. Wait for a subscription event with version >= this version to see the change. """ type CommandResult { id: ID! key: String version: Int! } type Comment { author: UserRef! """Empty on a deleted comment kept for its replies""" body: String! createdAt: String! decidedAt: String """Who marked it as a decision""" decidedBy: UserRef """Marked as a decision of the ticket (shown above it)""" decision: Boolean! """Deleted, but kept (without its text) while it has replies""" deleted: Boolean! editedAt: String id: ID! issueId: ID! """In the order they are offered; only the ones somebody chose""" reactions: [CommentReaction!]! """The top-level comment it answers; null for a top-level one""" replyTo: ID """A conversation (top-level comment and its replies) that was settled""" resolved: Boolean! resolvedAt: String """Who settled it""" resolvedBy: UserRef version: Int! } type CommentChange { action: String! actorId: ID! """Null when deleted""" comment: Comment commentId: ID! issueId: ID! version: Int! } type CommentPage { items: [Comment!]! total: Int! } """One emoji on a comment""" type CommentReaction { emoji: String! """Who chose it""" users: [UserRef!]! } type CountByAssignee { count: Int! """Null = unassigned""" user: UserRef } type CountByKey { count: Int! key: String! } type CountByStatus { count: Int! """Status id""" key: String! } input CreateAutomationInput { action: AutomationActionInput! conditions: AutomationConditionsInput name: String! projectId: ID! trigger: AutomationTriggerInput! } input CreateIssueInput { """An area id""" area: String assigneeId: ID """Only the fields to change""" customFields: [CustomFieldValueInput!] description: String dueDate: String """Figma frame for UI changes""" figmaUrl: String labels: [String!] """Epic or ticket of the same project the new one breaks down""" parentId: ID priority: IssuePriority projectId: ID! releaseId: ID """When work should start (roadmap), YYYY-MM-DD""" startDate: String storyPoints: Int """A team id""" team: String title: String! """A ticket type id""" type: String! } input CreateProjectInput { description: String """Readable by anyone, also without signing in""" isPublic: Boolean """2-10 chars, e.g. "TS" → tickets TS-1, TS-2...""" key: String! name: String! """ A project you own or administer to start from: its statuses, transitions, types, areas, custom fields and automation rules are copied """ templateProjectId: ID } input CreateReleaseInput { description: String """e.g. v1.4.0""" name: String! projectId: ID! targetDate: String } input CreateSprintInput { """YYYY-MM-DD, included""" endDate: String! goal: String name: String! projectId: ID! """YYYY-MM-DD""" startDate: String! } input CreateWebhookInput { """Event names, family.* or *""" events: [String!]! projectId: ID! url: String! } type CreatedResolved { created: Int! resolved: Int! """Monday of the week (YYYY-MM-DD)""" week: String! } type CumulativeFlow { dates: [String!]! series: [FlowSeries!]! } """A field the project adds to its tickets; its type never changes""" type CustomFieldDefinition { archived: Boolean! id: String! name: String! """The choices of a SELECT field""" options: [String!]! type: CustomFieldType! } input CustomFieldDefinitionInput { archived: Boolean! = false id: String! name: String! """The choices of a SELECT field""" options: [String!]! = [] type: CustomFieldType! } """What a custom field holds (DATE: YYYY-MM-DD)""" enum CustomFieldType { DATE NUMBER SELECT TEXT } """A ticket's value of a field""" type CustomFieldValue { fieldId: String! value: String! } """A custom field's value; null or '' clears it""" input CustomFieldValueInput { fieldId: String! value: String } """The project's link for clients (owners and admins)""" type DashboardShare { blocks: [String!]! createdAt: String! projectId: ID! """Secret of the link /share/{token}""" token: String! } """A comment marked as a decision, with its ticket""" type Decision { comment: Comment! issue: IssueParent! } """A commit, branch or pull request that mentions the ticket""" type DevLink { at: String! author: String kind: DevLinkKind! """github, gitea or gitlab""" provider: String! """Short SHA, branch or PR number""" ref: String! """The project's name for the repository it came from""" repository: String state: DevLinkState title: String! url: String! } enum DevLinkKind { BRANCH COMMIT PULL_REQUEST } enum DevLinkState { CLOSED MERGED OPEN } type DurationStats { averageDays: Float count: Int! """85% of tickets take at most this long""" p85Days: Float } """A top-level ticket that groups others, with their progress""" type Epic { issue: Issue! progress: ChildProgress! } """Bugs reported in the 14 days after a release shipped""" type EscapedBugs { bugs: Int! name: String! releaseId: ID! releasedAt: String! } """Open tickets per option of a list custom field""" type FieldBreakdown { counts: [OptionCount!]! fieldId: String! """Open tickets with no value""" none: Int! } type FirstSteps { calendar: Boolean! invited: Boolean! project: Boolean! ticket: Boolean! } type FlowSeries { counts: [Int!]! status: String! } """ Webhooks from GitHub, Gitea or GitLab: commits, branches and pull requests naming a ticket key are linked to it """ type GitIntegration { """On while there is at least one repository""" enabled: Boolean! repositories: [GitRepository!]! """Path of the webhook on this API, the same for every repository""" webhookPath: String! } """A repository whose webhooks the project accepts""" type GitRepository { createdAt: String! id: ID! """The project's name for it: api, web, admin…""" name: String! """Webhook secret of this repository; only owners and admins see it""" secret: String } """The home page beyond my work""" type Home { activity: [Activity!]! agenda: [AgendaItem!]! firstSteps: FirstSteps! me: MyWeek! online: [Online!]! projects: [HomeProject!]! sprints: [HomeSprint!]! suggestions: [Suggestion!]! team: TeamWeek! } type HomeProject { """Activity per day, last 14, oldest first""" activity: [Int!]! open: Int! overdue: Int! projectId: ID! sprint: HomeSprintBrief } type HomeSprint { projectKey: String! projectName: String! sprint: SprintPulse! } type HomeSprintBrief { behind: Boolean! name: String! percent: Int! } """A ticket the dashboard names, with the number that put it there""" type InsightIssue { assignee: UserRef """Days in its status (aging, stuck) or past / to its due date""" days: Float! dueDate: String id: ID! key: String! status: String! title: String! } type Issue { """Statuses this ticket can move to next (project's workflow)""" allowedTransitions: [String!]! """An area id""" area: String assignee: UserRef attachments: [Attachment!]! """ Open tickets it waits for: the ones that block it and the ones it depends on """ blockedBy: [IssueParent!]! checklist: [ChecklistItem!]! commentCount: Int! comments(limit: Int! = 50, offset: Int! = 0): CommentPage! createdAt: String! """Values of the project's custom fields (only those set)""" customFields: [CustomFieldValue!]! """Its comments marked as decisions, oldest first""" decisions: [Comment!]! description: String """Commits, branches and pull requests that mention it""" devLinks: [DevLink!]! dueDate: String figmaUrl: String """Whether I follow it with everything under it (false without a token)""" followingTree: Boolean! """History of this ticket""" history(limit: Int! = 50): [Activity!]! id: ID! """Human key, e.g. TS-42""" key: String! labels: [String!]! """Linked tickets I can see""" linkedIssues: [Issue!]! links: [IssueLink!]! number: Int! """The epic or ticket this one breaks down""" parent: IssueParent """Whether I pinned it (false without a token)""" pinned: Boolean! priority: IssuePriority! projectId: ID! projectKey: String! """ Place in the backlog and in its board column (ascending, compare as text) """ rank: String! release: ReleaseRef reporter: UserRef! sprint: SprintRef """When work should start (roadmap)""" startDate: String """A status id of the project's settings""" status: String! statusCategory: StatusCategory! storyPoints: Int """A team id""" team: String title: String! """In the trash since then; null when it is not""" trashedAt: String """A ticket type id of the project's settings""" type: String! updatedAt: String! version: Int! """Whether I voted for it""" voted: Boolean! """How many want it done""" votes: Int! """People following the ticket""" watchers: [UserRef!]! } type IssueChange { action: String! actorId: ID! issue: Issue! version: Int! } input IssueFilterInput { areas: [String!] assigneeId: ID categories: [StatusCategory!] """Only tickets holding these custom values""" customFields: [CustomFieldValueInput!] """Due on or after this day (YYYY-MM-DD)""" dueFrom: String """Due on or before this day (YYYY-MM-DD)""" dueTo: String labels: [String!] """Only tickets with no area""" noArea: Boolean """Only tickets nobody estimated""" noEstimate: Boolean """Only tickets in no sprint""" noSprint: Boolean """Only the tickets hanging from this one""" parentId: ID priorities: [IssuePriority!] projectId: ID! releaseId: ID """Matches key, title or description""" search: String sort: IssueSort = RECENT sprintId: ID statuses: [String!] """Team ids""" teams: [String!] types: [String!] unassigned: Boolean """Only tickets not updated since this instant (ISO)""" updatedBefore: String """Only the tickets I follow (none when anonymous)""" watching: Boolean } type IssueLink { """OUTWARD: this issue → other. INWARD: other → this issue.""" direction: LinkDirection! issueId: ID! issueKey: String! type: IssueLinkType! } enum IssueLinkType { BLOCKS DEPENDS_ON DUPLICATES RELATES_TO TESTS } type IssuePage { items: [Issue!]! total: Int! } """The ticket another one hangs from""" type IssueParent { id: ID! key: String! title: String! } enum IssuePriority { CRITICAL HIGH LOW LOWEST MEDIUM } """RECENT: last updated first. RANK: backlog order.""" enum IssueSort { RANK RECENT } """What a new ticket of the type starts with""" type IssueTemplate { """Steps added to every new ticket""" checklist: [String!]! """Used when the ticket comes without a description""" description: String } input IssueTemplateInput { checklist: [String!]! = [] description: String } type IssueTypeOption { archived: Boolean! color: String! icon: String! id: String! name: String! template: IssueTemplate } input IssueTypeOptionInput { archived: Boolean! = false """A palette colour (follows the theme) or #rrggbb""" color: String! icon: String! id: String! name: String! template: IssueTemplateInput } """ Where the time of the tickets done in the last 90 days went, created to done """ type Journey { """Part of the lead time in an in-progress status, 0-100""" flowEfficiency: Int leadDays: Float samples: Int! steps: [JourneyStep!]! } type JourneyStep { """Average days a closed ticket spent in it""" days: Float! """Its part of the whole lead time, 0-100""" share: Int! """Status id of the project settings""" status: String! } enum LinkDirection { INWARD OUTWARD } input LinkIssuesInput { issueId: ID! targetIssueId: ID! type: IssueLinkType! } type Me { """Roles inside the task-stream OAuth client""" appRoles: [String!]! email: String! id: ID! isActive: Boolean! name: String! """Global roles in Pireon""" roles: [String!]! } type Mutation { """Add a step to a ticket's checklist""" addChecklistItem(input: AddChecklistItemInput!): CommandResult! """ Comment on a ticket, or answer a comment (replyTo; one level of replies) """ addComment(body: String!, issueId: ID!, replyTo: ID): CommandResult! """ Add a repository with its own secret (the first turns the integration on) """ addGitRepository(name: String!, projectId: ID!): GitRepository! """Add a Pireon user to the project""" addProjectMember(input: ProjectMemberInput!): CommandResult! """ Archive the project (owner only): everything stays readable, nothing changes until it is unarchived """ archiveProject(projectId: ID!): CommandResult! archiveRelease( """ Open release of the same project that takes its unfinished tickets; none: they leave it """ moveTo: ID releaseId: ID! ): CommandResult! """Assign (or unassign with null) a project member""" assignIssue(assigneeId: ID, issueId: ID!): CommandResult! """ The same change on up to 100 tickets; each goes through the normal rules and may refuse on its own """ bulkUpdateIssues(input: BulkUpdateIssuesInput!): BulkResult! """Move a ticket through the workflow (incl. QA)""" changeIssueStatus(input: ChangeIssueStatusInput!): CommandResult! changeProjectMemberRole(input: ProjectMemberInput!): CommandResult! """ Close the sprint under way. Unfinished tickets move to carryOverToSprintId, or back to the backlog when it is null. """ closeSprint(carryOverToSprintId: ID, sprintId: ID!): CommandResult! """ Add a rule. It acts as TaskStream, within the workflow, and what it does triggers no other rule. """ createAutomation(input: CreateAutomationInput!): Automation! """A new secret calendar URL; the previous one stops working""" createCalendarFeed: CalendarFeed! createIssue(input: CreateIssueInput!): CommandResult! createProject(input: CreateProjectInput!): CommandResult! createRelease(input: CreateReleaseInput!): CommandResult! """Plan a sprint (owners and admins)""" createSprint(input: CreateSprintInput!): CommandResult! createWebhook(input: CreateWebhookInput!): WebhookCreated! deleteAutomation(automationId: ID!): Boolean! """Author or project admin""" deleteComment(commentId: ID!): CommandResult! """Delete one of my views""" deleteMyView(id: ID!): Boolean! """ Delete the project (owner only), with its tickets, comments and releases. `confirmKey` must be the project key. """ deleteProject(confirmKey: String!, projectId: ID!): CommandResult! """Delete a view: whoever saved it, or an admin if it is shared""" deleteSavedFilter(id: ID!): Boolean! """Delete a sprint that never started; its tickets go back to the backlog""" deleteSprint(sprintId: ID!): CommandResult! deleteWebhook(webhookId: ID!): Boolean! """Turn it off; the bugs it opened stay""" disableAlertIntegration(projectId: ID!): Boolean! """ A new ticket like this one: what it says, not where it stands (the key comes in the result) """ duplicateIssue(issueId: ID!): CommandResult! editComment(body: String!, commentId: ID!): CommandResult! """ Follow a ticket with everything under it (an epic): its changes and those of every ticket hanging from it, also future ones """ followTree(issueId: ID!): Boolean! """I left this ticket's page""" leavePresence(issueId: ID!): Boolean! """Relate tickets, e.g. FE DEPENDS_ON BE, QA TESTS FE""" linkIssues(input: LinkIssuesInput!): CommandResult! """ Mark a comment as a decision of its ticket, or unmark it (on: false). Whoever can change the ticket """ markDecision(commentId: ID!, on: Boolean! = true): CommandResult! """Mark these as read, or all of them when `ids` is omitted""" markNotificationsRead(ids: [ID!]): Boolean! """ Pin a ticket: keep it at hand on my home page and in search (private, at most 20) """ pinIssue(issueId: ID!): Boolean! """ Ship the release. Fails while it has unfinished tickets unless force = true. """ publishRelease(force: Boolean! = false, releaseId: ID!): CommandResult! """Move a ticket in the backlog, between two others of the same project""" rankIssue(input: RankIssueInput!): CommandResult! """React (👍 👎 😄 🎉 😕 ❤️ 🚀 👀) or take it back (on: false)""" reactToComment(commentId: ID!, emoji: String!, on: Boolean!): CommandResult! """ Remove a file from a ticket (whoever uploaded it, or an owner/admin). Upload with the REST API. """ removeAttachment(attachmentId: ID!, issueId: ID!): CommandResult! removeChecklistItem(issueId: ID!, itemId: ID!): CommandResult! """Remove a repository; what it linked stays on the tickets""" removeGitRepository(projectId: ID!, repositoryId: ID!): Boolean! removeProjectMember(projectId: ID!, userId: ID!): CommandResult! """ Settle a conversation (a top-level comment and its replies) or reopen it (resolved: false). A conclusion is added as a reply marked as a decision. Whoever can change the ticket """ resolveThread(commentId: ID!, conclusion: String, resolved: Boolean! = true): CommandResult! """Back from the trash""" restoreIssue(issueId: ID!): CommandResult! """My calendar URL stops working""" revokeCalendarFeed: Boolean! """A new secret URL; the old one stops working at once""" rotateAlertToken(projectId: ID!): AlertIntegration! """A new secret for a repository; the old one stops working""" rotateGitRepositorySecret(projectId: ID!, repositoryId: ID!): GitRepository! """ Turn alerts → bugs on, or change the type and priority it opens (the URL stays) """ saveAlertIntegration(input: AlertSettingsInput!, projectId: ID!): AlertIntegration! """Save the current board filters under a name (members of the project)""" saveFilter(input: SaveFilterInput!): ID! """Save a view of my work under a name""" saveMyView(input: SaveMyViewInput!): ID! """ Place a ticket under an epic or another ticket of the same project (null: back to the top). Three levels at most: epic → ticket → subtask. """ setIssueParent(issueId: ID!, parentId: ID): CommandResult! """Put a ticket in a release (null removes it)""" setIssueRelease(issueId: ID!, releaseId: ID): CommandResult! """Put a ticket in a sprint (null: back to the backlog)""" setIssueSprint(issueId: ID!, sprintId: ID): CommandResult! """Turn the link on or change its blocks; renew for a new secret""" shareDashboard(input: ShareDashboardInput!): DashboardShare! """Start a planned sprint (only one under way per project)""" startSprint(sprintId: ID!): CommandResult! """Push on this device""" subscribePush(subscription: PushSubscriptionInput!): Boolean! """Send a ping now and tell how it went""" testWebhook(webhookId: ID!): WebhookDelivery! """ I am on this ticket (send every ~10 s while the page is open): answers who else is, the ones editing first """ touchPresence(editing: Boolean! = false, issueId: ID!): [Presence!]! """ To the trash (whoever opened it, or an owner/admin): hidden everywhere, deleted for good after 30 days """ trashIssue(issueId: ID!): CommandResult! """ I am writing on this ticket (send every few seconds while typing): those with it open see it at once via `typing` """ typing( issueId: ID! """The conversation being answered; null: a new comment""" threadId: ID ): Boolean! """Bring an archived project back (owner only)""" unarchiveProject(projectId: ID!): CommandResult! """Stop following a ticket with everything under it""" unfollowTree(issueId: ID!): Boolean! unlinkIssues(input: LinkIssuesInput!): CommandResult! """Unpin a ticket""" unpinIssue(issueId: ID!): Boolean! """The link stops working""" unshareDashboard(projectId: ID!): Boolean! """Push off on this device""" unsubscribePush(endpoint: String!): Boolean! """Stop following a ticket""" unwatchIssue(issueId: ID!): CommandResult! """Rename, pause or resume""" updateAutomation(active: Boolean, automationId: ID!, name: String): Automation! """Reword, tick or untick a checklist step""" updateChecklistItem(input: UpdateChecklistItemInput!): CommandResult! updateIssue(input: UpdateIssueInput!): CommandResult! updateNotificationSettings(email: Boolean!): NotificationSettings! updateProject(input: UpdateProjectInput!): CommandResult! """ Replace statuses, transitions, ticket types and areas (owners and admins). Values can be archived, not deleted. """ updateProjectSettings(projectId: ID!, settings: ProjectSettingsInput!): CommandResult! updateRelease(input: UpdateReleaseInput!): CommandResult! updateSprint(input: UpdateSprintInput!): CommandResult! updateWebhook(input: UpdateWebhookInput!): Webhook! """ Vote for a ticket (on) or take the vote back: anyone signed in on a public project, members on a private one """ voteIssue(issueId: ID!, on: Boolean!): CommandResult! """ Follow a ticket: be told when it moves, is reassigned or gets a comment """ watchIssue(issueId: ID!): CommandResult! """ Write the release notes (Markdown; null removes them). Also after shipping. """ writeReleaseNotes(notes: String, releaseId: ID!): CommandResult! } type MyNotifications { items: [Notification!]! """All my unread ones, not just these""" unread: Int! } """A named view of my work (private)""" type MyView { createdAt: String! criteria: MyViewCriteria! id: ID! name: String! } """What a view of my work narrows to; empty: every ticket of my projects""" type MyViewCriteria { assignedToMe: Boolean """Only types with the bug icon""" bugsOnly: Boolean categories: [StatusCategory!] """Only open tickets past due""" overdue: Boolean priorities: [IssuePriority!] """Empty: all my projects""" projectIds: [ID!] search: String watching: Boolean } input MyViewCriteriaInput { assignedToMe: Boolean bugsOnly: Boolean categories: [StatusCategory!] overdue: Boolean priorities: [IssuePriority!] """Empty: all my projects""" projectIds: [ID!] search: String watching: Boolean } type MyWeek { lastWeek: Int! """Days in a row with something finished""" streak: Int! thisWeek: Int! } type Notification { actor: UserRef! createdAt: String! id: ID! issueId: ID issueKey: String kind: NotificationKind! projectId: ID! projectKey: String! """Null: unread""" readAt: String summary: String! } """Why someone is told""" enum NotificationKind { ADDED_TO_PROJECT ASSIGNED COMMENTED MENTIONED PROPOSED QA_FAILED REMINDER REPLIED STATUS_CHANGED WATCHED } type NotificationSettings { """Copies by e-mail""" email: Boolean! """Whether this installation can send e-mail at all""" emailAvailable: Boolean! """ VAPID public key to subscribe a device to push with; null: no push here """ pushPublicKey: String } """Someone of my projects on a ticket now""" type Online { at: String! editing: Boolean! issueKey: String issueTitle: String projectKey: String! user: UserRef! } type OptionCount { count: Int! value: String! } """ One of my active projects at a glance: open work, risks, sprint, releases and epics """ type PortfolioProject { blocked: Int! """Open epics, nearest due date first (six at most)""" epics: [Epic!]! isPublic: Boolean! key: String! name: String! open: Int! overdue: Int! projectId: ID! releases: [ReleaseForecast!]! sprint: SprintPulse stuck: Int! total: Int! updatedAt: String! } """Someone on a ticket right now (heartbeat in the last 30 s)""" type Presence { """Last heartbeat""" at: String! """Editing the ticket or writing a comment""" editing: Boolean! user: UserRef! } type PriorityCount { count: Int! priority: IssuePriority! } type Project { """Takes bug reports and ideas from anyone (while public)""" acceptsProposals: Boolean! """ Statistics of the last `days` days (7-365): created vs resolved, cumulative flow, cycle/lead time, throughput and QA """ analytics(days: Int! = 90): ProjectAnalytics! """Archived since then (read-only); null while active""" archivedAt: String """Kanban board, one column per status""" board( area: String assigneeId: ID labels: [String!] perColumn: Int! = 50 priorities: [IssuePriority!] releaseId: ID """Matches key, title or description""" search: String sprintId: ID types: [String!] unassigned: Boolean ): [BoardColumn!]! createdAt: String! description: String id: ID! """ The dashboard: sprint under way, overdue / blocked / stuck tickets, aging and bottlenecks """ insights( """ISO instant (e.g. my last visit): also tell what changed after it""" since: String ): ProjectInsights! """Anyone can read it, also without signing in""" isPublic: Boolean! key: String! members: [ProjectMember!]! name: String! owner: UserRef! releases: [Release!]! settings: ProjectSettings! """Project tracking dashboard""" stats: ProjectStats! updatedAt: String! version: Int! } type ProjectAnalytics { createdVsResolved: [CreatedResolved!]! """Tickets in each status at the end of every day""" cumulativeFlow: CumulativeFlow! """Start of work → done""" cycleTime: DurationStats! from: String! """Creation → done""" leadTime: DurationStats! qa: QaStats! """Finished per person and week""" throughput: [Throughput!]! to: String! } type ProjectChange { action: String! actorId: ID! project: Project! version: Int! } """ The dashboard: sprint under way, risks, aging, bottlenecks, release forecasts, team load, backlog health and changes """ type ProjectInsights { aging: Aging! backlog: BacklogHealth! bottlenecks: [StatusTime!]! """Only when asked with `since`""" changes: ChangesSince """One per active list custom field""" fields: [FieldBreakdown!]! generatedAt: String! """The last 12 weeks from a Monday, oldest first (84 days)""" heatmap: [ActivityDay!]! journey: Journey! """Null while the project has never had a proposal""" proposals: ProposalsFunnel quality: Quality! releases: [ReleaseForecast!]! risks: Risks! sprint: SprintPulse team: [TeamLoad!]! } type ProjectMember { role: ProjectRole! user: UserRef! } input ProjectMemberInput { projectId: ID! role: ProjectRole! = MEMBER """Pireon user id""" userId: ID! } enum ProjectRole { ADMIN GUEST MEMBER OWNER VIEWER } """ Statuses (board order), transitions, ticket types, areas and custom fields """ type ProjectSettings { areas: [AreaOption!]! """ Definition of done: tickets reach DONE only with their checklist ticked (owners and admins may override) """ checklistBeforeDone: Boolean! customFields: [CustomFieldDefinition!]! issueTypes: [IssueTypeOption!]! statuses: [WorkflowStatus!]! teams: [Team!]! transitions: [StatusTransitions!]! } """ The whole configuration (replaces the previous one). Statuses go in board order. """ input ProjectSettingsInput { areas: [AreaOptionInput!]! """ Definition of done: DONE only with the checklist ticked. Absent: unchanged """ checklistBeforeDone: Boolean """Absent: unchanged. Fields cannot be removed: archive them.""" customFields: [CustomFieldDefinitionInput!] issueTypes: [IssueTypeOptionInput!]! statuses: [WorkflowStatusInput!]! """Absent: unchanged. Teams cannot be removed: archive them.""" teams: [TeamInput!] transitions: [StatusTransitionsInput!]! } type ProjectStats { byArea: [CountByKey!]! """Open tickets per person""" byAssignee: [CountByAssignee!]! byPriority: [CountByKey!]! byStatus: [CountByStatus!]! byType: [CountByKey!]! open: Int! total: Int! } """The public's proposals, from received to done or discarded""" type ProposalsFunnel { discarded: Int! done: Int! received: Int! """In the last 30 days""" receivedLately: Int! """Most voted waiting, at most 5""" topWaiting: [WaitingProposal!]! underWay: Int! """Open, not started, in no sprint nor release""" waiting: Int! } """A browser's Web Push subscription (PushSubscription.toJSON())""" input PushSubscriptionInput { auth: String! endpoint: String! p256dh: String! } """QA verdicts per area (90 days)""" type QaByArea { """Null: no area""" area: String passed: Int! returned: Int! } type QaStats { failed: Int! failureRate: Float passed: Int! } """Bugs (types with the bug icon) and QA""" type Quality { """Last 8 weeks, oldest first""" bugWeeks: [BugWeek!]! escaped: [EscapedBugs!]! openBugsByPriority: [PriorityCount!]! qaByArea: [QaByArea!]! } type Query { """Project activity feed (newest first)""" activity( """ ISO date: only activity at or after it (with before, a window such as a day) """ after: String """ISO date cursor""" before: String issueId: ID limit: Int! = 50 projectId: ID! ): [Activity!]! alertIntegration(projectId: ID!): AlertIntegration! automations(projectId: ID!): [Automation!]! """The project's link for clients, if any (owners and admins)""" dashboardShare(projectId: ID!): DashboardShare """ Decisions by their text, most recent first: of a project, or of all my projects without one """ decisions(limit: Int! = 20, projectId: ID, search: String): [Decision!]! """ A project's epics: top-level tickets that group others, with the progress of those """ epics(projectId: ID!): [Epic!]! gitIntegration(projectId: ID!): GitIntegration! issue( """Issue id or key (e.g. "TS-42")""" idOrKey: String! ): Issue! issues(filter: IssueFilterInput!, limit: Int! = 50, offset: Int! = 0): IssuePage! """The authenticated user""" me: Me! """My calendar URL, if I made one""" myCalendarFeed: CalendarFeed """ The home page beyond my work: agenda of the week, activity of my projects, the week in numbers, sprints, project cards, suggestions, first steps and who is on what now """ myHome: Home! """ Tickets across all my projects: assigned to me (default) or any (e.g. categories [QA]) """ myIssues( assignedToMe: Boolean! = true """Only types drawn with the bug icon""" bugsOnly: Boolean categories: [StatusCategory!] limit: Int! = 50 offset: Int! = 0 """Only open tickets past their due date""" overdue: Boolean priorities: [IssuePriority!] """Only these of my projects""" projectIds: [ID!] """Matches key, title or description (global search)""" search: String statuses: [String!] """Only the tickets I follow""" watching: Boolean! = false ): IssuePage! """My notifications, newest first, and how many are unread""" myNotifications(limit: Int! = 30, unreadOnly: Boolean! = false): MyNotifications! """ My pinned tickets, most recently pinned first (trashed or out of reach left out) """ myPins: [Issue!]! """Projects where I am a member""" myProjects: [Project!]! """My saved views of my work, across my projects""" myViews: [MyView!]! notificationSettings: NotificationSettings! """ My active projects (not archived, not as a guest) at a glance: open work, risks, sprint, release forecasts and epics """ portfolio: [PortfolioProject!]! """A project of mine, or any public one (no sign-in needed)""" project( """Project id or key (e.g. "TS")""" idOrKey: String! ): Project! """Projects anyone can read, also without signing in""" publicProjects: [Project!]! release(id: ID!): Release! """My views of the project's board, then the shared ones""" savedFilters(projectId: ID!): [SavedFilter!]! """What a link for clients shows, for anyone with it""" sharedDashboard(token: String!): SharedDashboard sprint(id: ID!): Sprint! """ A project's sprints: the one under way, the planned ones, then the closed ones """ sprints(projectId: ID!): [Sprint!]! """A project's tickets in the trash, newest first""" trash(projectId: ID!): [Issue!]! """Planned releases of all my projects, soonest target date first""" upcomingReleases(limit: Int! = 10): [Release!]! user(id: String!): User """Search users by name or email (to assign / add members)""" users(limit: Int! = 20, search: String! = ""): [User!]! """Event names a webhook can subscribe to (also family.* and *)""" webhookEvents: [String!]! webhooks(projectId: ID!): [Webhook!]! } input RankIssueInput { """The ticket that ends up right above (null: the top)""" aboveIssueId: ID """The ticket that ends up right below (null: the bottom)""" belowIssueId: ID issueId: ID! } type Release { """Scope vs finished tickets, day by day""" burnup: ReleaseBurnup! createdAt: String! description: String id: ID! """Tickets included in this release""" issues(limit: Int! = 100, offset: Int! = 0): IssuePage! name: String! """What shipped, told for people (Markdown)""" notes: String """ A Markdown draft of the notes from its finished tickets, by type (not saved) """ notesDraft: String! progress: ReleaseProgress! projectId: ID! releasedAt: String status: ReleaseStatus! targetDate: String version: Int! } type ReleaseBurnup { dates: [String!]! done: [Int!]! releaseId: ID! """Tickets in the release (not cancelled)""" scope: [Int!]! targetDate: String } type ReleaseChange { action: String! actorId: ID! release: Release! version: Int! } """When a planned release would be finished, at the real pace""" type ReleaseForecast { finished: Int! """Half of the simulated futures finish by then""" likelyDate: String name: String! releaseId: ID! """85% finish by then""" safeDate: String targetDate: String total: Int! """DONE, NO_DATE, UNKNOWN (no pace yet), ON_TRACK, AT_RISK or LATE""" verdict: String! } type ReleaseProgress { byStatus: [CountByStatus!]! finished: Int! percent: Int! total: Int! } type ReleaseRef { id: ID! name: String! } enum ReleaseStatus { ARCHIVED PLANNED RELEASED } """Tickets to look at now (worst first)""" type Risks { blocked: [InsightIssue!]! blockedCount: Int! """Due within 7 days""" dueSoon: [InsightIssue!]! dueSoonCount: Int! overdue: [InsightIssue!]! overdueCount: Int! stuck: [InsightIssue!]! stuckCount: Int! stuckDays: Int! } input SaveFilterInput { criteria: SavedFilterCriteriaInput! name: String! projectId: ID! """Visible to the whole project (members, not viewers, share)""" shared: Boolean! = false } input SaveMyViewInput { criteria: MyViewCriteriaInput! name: String! } """ A named view of the board: private to whoever saved it, or shared with the project """ type SavedFilter { createdAt: String! criteria: SavedFilterCriteria! id: ID! name: String! owner: UserRef! projectId: ID! shared: Boolean! } """What a saved view narrows the board to; empty: everything""" type SavedFilterCriteria { areas: [String!] assigneeId: ID labels: [String!] priorities: [IssuePriority!] releaseId: ID search: String types: [String!] unassigned: Boolean } input SavedFilterCriteriaInput { areas: [String!] assigneeId: ID labels: [String!] priorities: [IssuePriority!] releaseId: ID search: String types: [String!] unassigned: Boolean } """The project's link for clients""" input ShareDashboardInput { """Blocks to show: flow, sprint, releases, epics, activity""" blocks: [String!]! projectId: ID! """A new secret: the old link stops working""" renew: Boolean } """ What a link for clients shows: only the chosen blocks (the others are null) """ type SharedDashboard { activity: [ActivityDay!] blocks: [String!]! epics: [SharedEpic!] flow: [SharedFlow!] generatedAt: String! projectKey: String! projectName: String! releases: [ReleaseForecast!] sprint: SprintPulse } """An open epic and how far it got""" type SharedEpic { done: Int! dueDate: String key: String! percent: Int! title: String! total: Int! } """Tickets in one status""" type SharedFlow { """A colour name of the project settings""" color: String! count: Int! name: String! status: String! } """A time-boxed iteration: the tickets the team commits to""" type Sprint { burndown: SprintBurndown! closedAt: String createdAt: String! """Last day (included), YYYY-MM-DD""" endDate: String! goal: String id: ID! """Tickets in this sprint, in backlog order""" issues(limit: Int! = 100, offset: Int! = 0): IssuePage! name: String! progress: SprintProgress! projectId: ID! """First day, YYYY-MM-DD""" startDate: String! startedAt: String status: SprintStatus! version: Int! } """ Per day of the sprint: tickets in it, still open, and their points (null: days to come). `ideal` falls from the first day to zero. """ type SprintBurndown { dates: [String!]! ideal: [Float!]! remaining: [Int]! remainingPoints: [Int]! scope: [Int]! sprintId: ID! } type SprintChange { action: String! actorId: ID! """Null: deleted""" sprint: Sprint sprintId: ID! version: Int! } type SprintProgress { """Done or cancelled""" finished: Int! finishedStoryPoints: Int! percent: Int! storyPoints: Int! total: Int! } """The sprint under way: time gone against work done""" type SprintPulse { """At this pace, what is open would not be closed""" behind: Boolean! """Days left after today""" daysLeft: Int! donePoints: Int! doneTickets: Int! endDate: String! name: String! neededPerDay: Float pacePerDay: Float points: Int! sprintId: ID! startDate: String! tickets: Int! totalDays: Int! } type SprintRef { id: ID! name: String! } """PLANNED, ACTIVE (one per project at a time) or CLOSED""" enum SprintStatus { ACTIVE CLOSED PLANNED } """ What a status means, whatever each project calls it. DONE and CANCELLED are finished. """ enum StatusCategory { CANCELLED DONE IN_PROGRESS QA TODO } type StatusTime { averageDays: Float open: Int! overLimit: Boolean! samples: Int! status: String! wipLimit: Int } type StatusTransitions { from: String! to: [String!]! } input StatusTransitionsInput { from: String! to: [String!]! } type Subscription { """Live activity feed""" activityAdded(projectId: ID!): Activity! commentChanged(issueId: ID!): CommentChange! """Tickets created/updated/moved in a project (board in realtime)""" issueChanged(projectId: ID!): IssueChange! """Projects I am added to / removed from""" myProjectsChanged: ProjectChange! """My notifications, as they happen""" notificationAdded: Notification! projectChanged(projectId: ID!): ProjectChange! releaseChanged(projectId: ID!): ReleaseChange! sprintChanged(projectId: ID!): SprintChange! """ Who is writing on a ticket, as they type (one's own come too: leave them out) """ typing(issueId: ID!): Typing! } type Suggestion { count: Int! """UNASSIGNED, PROPOSALS or QA_WAITING""" kind: String! projectKey: String! } """A group of members: tickets go to it; @team mentions tell them all""" type Team { archived: Boolean! id: String! memberIds: [ID!]! name: String! } input TeamInput { archived: Boolean! = false id: String! memberIds: [ID!]! = [] name: String! } type TeamLoad { blocked: Int! openPoints: Int! openTickets: Int! overloaded: Boolean! """Points closed per sprint, last three closed sprints""" pointsPerSprint: Float user: UserRef! } type TeamWeek { lastWeek: Int! """Finished per day, last 14, oldest first""" perDay: [Int!]! thisWeek: Int! } type Throughput { count: Int! user: UserRef week: String! } """Someone writing on a ticket right now (not stored)""" type Typing { at: String! issueId: ID! """The conversation being answered; null: a new comment""" threadId: ID user: UserRef! } input UpdateChecklistItemInput { done: Boolean issueId: ID! itemId: ID! text: String } input UpdateIssueInput { """An area id""" area: String """Only the fields to change""" customFields: [CustomFieldValueInput!] description: String dueDate: String """Figma frame for UI changes""" figmaUrl: String issueId: ID! labels: [String!] priority: IssuePriority """When work should start (roadmap), YYYY-MM-DD""" startDate: String storyPoints: Int """A team id""" team: String title: String type: String } input UpdateProjectInput { """ Take bug reports and ideas from anyone through the public form (while public) """ acceptsProposals: Boolean description: String isPublic: Boolean name: String projectId: ID! } input UpdateReleaseInput { description: String name: String releaseId: ID! targetDate: String } input UpdateSprintInput { endDate: String goal: String name: String sprintId: ID! startDate: String } input UpdateWebhookInput { active: Boolean events: [String!] url: String webhookId: ID! } """User managed by the Pireon identity server""" type User { email: String! id: ID! isActive: Boolean! name: String! } type UserRef { id: ID! name: String! } type WaitingProposal { """Days since it came in""" days: Int! id: ID! key: String! title: String! votes: Int! } """ Where the project tells another system what happened (signed POST, HMAC-SHA256) """ type Webhook { active: Boolean! createdAt: String! createdBy: UserRef! """Event names, family.* or *""" events: [String!]! id: ID! lastDelivery: WebhookDelivery projectId: ID! url: String! } type WebhookCreated { id: ID! """Signs every delivery. Shown only now: keep it.""" secret: String! } type WebhookDelivery { at: String! error: String event: String! ok: Boolean! """HTTP status""" status: Int } type WorkflowStatus { """No new tickets or transitions into it""" archived: Boolean! category: StatusCategory! """A palette colour (slate, violet, green…, follows the theme) or #rrggbb""" color: String! """Stable id stored on tickets, e.g. IN_REVIEW""" id: String! name: String! """Entering it needs a reason""" requiresReason: Boolean! """ Work-in-progress limit: most tickets the column should hold (a warning, not a lock) """ wipLimit: Int } input WorkflowStatusInput { archived: Boolean! = false category: StatusCategory! """A palette colour (follows the theme) or #rrggbb""" color: String! id: String! name: String! requiresReason: Boolean! = false """Work-in-progress limit (null: none)""" wipLimit: Int }