openapi: 3.0.0 info: title: Craft.io Portfolio API description: REST API providing access to portfolio data including portfolio items, portfolio custom fields, and terminology for enterprise product portfolio management. version: 1.0.0 contact: name: Craft.io Support url: https://help.craft.io/ email: support@craft.io servers: - url: / paths: /portfolios/{accountId}: get: operationId: GetPortfolios responses: '200': description: A list of portfolios content: application/json: schema: items: $ref: '#/components/schemas/Portfolio' type: array examples: Example 1: value: - id: string name: string workspaces: - id: string name: string key: string '400': description: Invalid account ID content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '401': description: No access to account content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '500': description: An error occurred while fetching portfolios content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' description: Get the list of your account’s portfolios and the workspaces they are connected with tags: - Portfolios security: - api_key: - read:portfolios:craft parameters: - in: path name: accountId required: true schema: type: string /portfolio/{portfolioId}/portfolio_fields: get: operationId: GetPortfolioCustomFields responses: '200': description: A list of portfolio fields and their metadata content: application/json: schema: items: $ref: '#/components/schemas/CustomField' type: array '400': description: Invalid portfolio ID content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '401': description: No access to portfolio content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '500': description: An error occurred while fetching portfolio fields content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' description: Get the list of portfolio fields and their metadata tags: - Portfolios security: - api_key: - read:portfolios:craft parameters: - in: path name: portfolioId required: true schema: type: string /portfolio/{portfolioId}/terminology: get: operationId: GetPortfolioTerminology responses: '200': description: A list of portfolio entities terminology content: application/json: schema: $ref: '#/components/schemas/TerminologyList_Terminology_' '400': description: Invalid portfolio ID content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '401': description: No access to portfolio content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '403': description: Access denied content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' '500': description: An error occurred while fetching terminology content: application/json: schema: $ref: '#/components/schemas/GeneralErrorResponse' description: Get the list of the portfolio entities terminology tags: - Portfolios security: - api_key: - read:portfolios:craft parameters: - in: path name: portfolioId required: true schema: type: string components: examples: {} headers: {} parameters: {} requestBodies: {} responses: {} schemas: Workspace: properties: id: type: string name: type: string nullable: true key: type: string webUrl: type: string description: Canonical Craft.io app URL for this workspace. Computed in PublishService. type: object additionalProperties: false GeneralErrorResponse: properties: message: type: string required: - message type: object additionalProperties: false CustomFieldOption: properties: id: type: string label: type: string startDate: type: string nullable: true endDate: type: string nullable: true required: - id - label type: object additionalProperties: false OptionShape: type: string enum: - select - date - date_range CustomField: properties: id: type: string name: type: string type: type: string values: items: type: string type: array options: items: $ref: '#/components/schemas/CustomFieldOption' type: array optionShape: $ref: '#/components/schemas/OptionShape' required: - id - name - type type: object additionalProperties: false Terminology: properties: category: type: string default: type: string customSingle: type: string customPlural: type: string required: - category - default - customSingle type: object additionalProperties: false TerminologyList_Terminology_: properties: {} type: object additionalProperties: $ref: '#/components/schemas/Terminology' Portfolio: properties: id: type: string name: type: string nullable: true workspaces: items: $ref: '#/components/schemas/Workspace' type: array webUrl: type: string description: Canonical Craft.io app URL for this portfolio. Computed in PublishService. required: - workspaces type: object additionalProperties: false SlackConnection: properties: workspaceId: type: string token: type: string slackTeamId: type: string slackInstallation: type: string isActive: type: boolean type: object additionalProperties: false SlackPortal: properties: workspaceId: type: string portalId: type: string portalName: type: string token: type: string type: object additionalProperties: false TeamInfo: properties: installation: $ref: '#/components/schemas/SlackConnection' portalList: items: $ref: '#/components/schemas/SlackPortal' type: array required: - installation - portalList type: object additionalProperties: false SlackTeamInfo: $ref: '#/components/schemas/TeamInfo' ConnectionUpdateRequest: properties: slackTeamId: type: string slackTeamName: type: string slackEnterpriseId: type: string slackEnterpriseName: type: string slackInstallation: type: string required: - slackInstallation type: object additionalProperties: false ApiKeyIntrospection: description: 'Introspection endpoints for "what is the current API key allowed to do". Used by clients (notably the MCP server) to self-filter the tools they expose.' properties: userId: type: string description: The user this key authenticates as. accountId: type: string description: The account this key belongs to. scopes: items: type: string type: array description: Granted granular scope strings (already normalized). resourceScope: properties: feedback_portals: items: type: string type: array nullable: true portfolios: items: type: string type: array nullable: true workspaces: items: type: string type: array nullable: true type: object description: 'Optional resource-scope narrowing. When a dimension is null/missing the key has access to every instance the bound user can see; when present it is the exclusive allowlist of ids on that dimension.' mcpAccess: type: boolean required: - userId - accountId - scopes - resourceScope - mcpAccess type: object additionalProperties: false Entity: properties: id: type: string name: type: string nullable: true type: object additionalProperties: false NullableType_Entity_: allOf: - $ref: '#/components/schemas/Entity' nullable: true NullableType_Entity-Array_: items: $ref: '#/components/schemas/Entity' type: array nullable: true Persona: properties: id: type: string name: type: string nullable: true position: type: string required: - position type: object additionalProperties: false NullableType_Persona_: allOf: - $ref: '#/components/schemas/Persona' nullable: true NullableType_Persona-Array_: items: $ref: '#/components/schemas/Persona' type: array nullable: true EntityWithDates: properties: id: type: string name: type: string nullable: true startDate: type: string nullable: true endDate: type: string nullable: true type: object additionalProperties: false NullableType_EntityWithDates_: allOf: - $ref: '#/components/schemas/EntityWithDates' nullable: true EntityWithTerminology: properties: id: type: string name: type: string nullable: true customTermName: type: string type: object additionalProperties: false NullableType_EntityWithTerminology-and-EntityWithDates_: allOf: - $ref: '#/components/schemas/EntityWithTerminology' - $ref: '#/components/schemas/EntityWithDates' nullable: true Assignee: properties: id: type: string team: type: string user: type: string required: - id - team type: object additionalProperties: false NullableType_Assignee_: allOf: - $ref: '#/components/schemas/Assignee' nullable: true EntityParent: properties: id: type: string title: type: string shortId: type: string webUrl: type: string description: Direct link to the parent item in the Craft.io app. required: - id type: object additionalProperties: false NullableType_EntityParent_: allOf: - $ref: '#/components/schemas/EntityParent' nullable: true NullableType_string_: type: string nullable: true NullableType_string-Array_: items: type: string type: array nullable: true CustomFieldValue: properties: id: type: string name: type: string value: $ref: '#/components/schemas/NullableType_string_' values: $ref: '#/components/schemas/NullableType_string-Array_' label: type: string required: - id type: object additionalProperties: false OutIn: properties: quarter: type: boolean sprint: type: boolean type: object additionalProperties: false Dependency: properties: id: type: string name: type: string value: type: string enum: - blocks - blocked by - related workspaceId: type: string portfolioId: type: string required: - id - value type: object additionalProperties: false NullableType__id%3F%3Astring.name%3F%3Astring__: properties: name: type: string id: type: string type: object nullable: true FeedbackLink: properties: id: type: string shortId: type: string title: type: string status: $ref: '#/components/schemas/NullableType__id%3F%3Astring.name%3F%3Astring__' webUrl: type: string description: Direct link into the feedback portal for this linked feedback item. type: object additionalProperties: false NullableType_FeedbackLink-Array_: items: $ref: '#/components/schemas/FeedbackLink' type: array nullable: true NullableType_Date_: type: string format: date-time nullable: true DevToolKeyList: properties: jira: type: string ado: type: string github: type: string gitlab: type: string pivotaltracker: type: string targetprocess: type: string type: object additionalProperties: false Item: properties: id: $ref: '#/components/schemas/NullableType_string_' type: type: string workspaceId: type: string portfolioId: type: string shortId: type: string title: type: string description: type: string nullable: true creationTime: type: string format: date-time updateTime: type: string format: date-time storyPoints: type: number format: double initiativeId: $ref: '#/components/schemas/NullableType_string_' value: type: number format: double effort: type: number format: double kano: type: string estimatedHours: type: number format: double labels: items: type: string type: array actualStartDate: $ref: '#/components/schemas/NullableType_Date_' actualEndDate: $ref: '#/components/schemas/NullableType_Date_' devToolKey: $ref: '#/components/schemas/DevToolKeyList' webUrl: type: string description: Canonical Craft.io app URL for this item. Computed in PublishService. status: $ref: '#/components/schemas/NullableType_Entity_' importance: $ref: '#/components/schemas/NullableType_Entity_' objective: $ref: '#/components/schemas/NullableType_Entity_' keyResult: $ref: '#/components/schemas/NullableType_Entity_' objectives: $ref: '#/components/schemas/NullableType_Entity-Array_' keyResults: $ref: '#/components/schemas/NullableType_Entity-Array_' persona: $ref: '#/components/schemas/NullableType_Persona_' personas: $ref: '#/components/schemas/NullableType_Persona-Array_' sprint: $ref: '#/components/schemas/NullableType_EntityWithDates_' quarter: $ref: '#/components/schemas/NullableType_EntityWithTerminology-and-EntityWithDates_' assignee: $ref: '#/components/schemas/NullableType_Assignee_' parent: $ref: '#/components/schemas/NullableType_EntityParent_' createdBy: $ref: '#/components/schemas/Entity' customFields: items: $ref: '#/components/schemas/CustomFieldValue' type: array outIn: $ref: '#/components/schemas/OutIn' dependencies: items: $ref: '#/components/schemas/Dependency' type: array feedbackLinks: $ref: '#/components/schemas/NullableType_FeedbackLink-Array_' type: object additionalProperties: false ItemFlat: properties: id: $ref: '#/components/schemas/NullableType_string_' type: type: string workspaceId: type: string portfolioId: type: string shortId: type: string title: type: string description: type: string nullable: true creationTime: type: string format: date-time updateTime: type: string format: date-time storyPoints: type: number format: double initiativeId: $ref: '#/components/schemas/NullableType_string_' value: type: number format: double effort: type: number format: double kano: type: string estimatedHours: type: number format: double labels: items: type: string type: array actualStartDate: $ref: '#/components/schemas/NullableType_Date_' actualEndDate: $ref: '#/components/schemas/NullableType_Date_' devToolKey: $ref: '#/components/schemas/DevToolKeyList' webUrl: type: string description: Canonical Craft.io app URL for this item. Computed in PublishService. status_id: type: string status_name: type: string importance_id: type: string importance_name: type: string objective_id: type: string objective_name: type: string keyResult_id: type: string keyResult_name: type: string persona_id: type: string persona_name: type: string sprint_id: type: string sprint_name: type: string quarter_id: type: string quarter_name: type: string assignee_id: type: string assignee_team: type: string assignee_user: type: string parent_id: type: string nullable: true parent_name: type: string nullable: true parent_shortId: type: string nullable: true devToolKey_jira: type: string devToolKey_ado: type: string devToolKey_github: type: string devToolKey_gitlab: type: string devToolKey_pivotaltracker: type: string devToolKey_targetprocess: type: string sprint_startDate: type: string nullable: true sprint_endDate: type: string nullable: true quarter_startDate: type: string nullable: true quarter_endDate: type: string nullable: true type: object additionalProperties: anyOf: - type: string - items: type: string type: array - type: boolean - type: string format: date-time - type: number format: double - $ref: '#/components/schemas/DevToolKeyList' nullable: true PaginationMetadata: properties: currentPage: type: number format: double perPage: type: number format: double totalPages: type: number format: double totalRecords: type: number format: double required: - currentPage - perPage - totalPages - totalRecords type: object additionalProperties: false ItemsPaginated_Item_: properties: items: items: $ref: '#/components/schemas/Item' type: array metadata: $ref: '#/components/schemas/PaginationMetadata' required: - items - metadata type: object additionalProperties: false ItemsPaginated_ItemFlat_: properties: items: items: $ref: '#/components/schemas/ItemFlat' type: array metadata: $ref: '#/components/schemas/PaginationMetadata' required: - items - metadata type: object additionalProperties: false ? Pick_Item.Exclude_keyofItem.workspaceId-or-initiativeId-or-sprint-or-quarter-or-assignee-or-storyPoints-or-estimatedHours-or-objective-or-keyResult-or-persona-or-personas-or-parent-or-labels-or-kano__ : properties: status: $ref: '#/components/schemas/NullableType_Entity_' importance: $ref: '#/components/schemas/NullableType_Entity_' objectives: $ref: '#/components/schemas/NullableType_Entity-Array_' keyResults: $ref: '#/components/schemas/NullableType_Entity-Array_' createdBy: $ref: '#/components/schemas/Entity' customFields: items: $ref: '#/components/schemas/CustomFieldValue' type: array outIn: $ref: '#/components/schemas/OutIn' dependencies: items: $ref: '#/components/schemas/Dependency' type: array feedbackLinks: $ref: '#/components/schemas/NullableType_FeedbackLink-Array_' id: $ref: '#/components/schemas/NullableType_string_' type: type: string portfolioId: type: string shortId: type: string title: type: string description: type: string nullable: true creationTime: type: string format: date-time updateTime: type: string format: date-time value: type: number format: double effort: type: number format: double actualStartDate: $ref: '#/components/schemas/NullableType_Date_' actualEndDate: $ref: '#/components/schemas/NullableType_Date_' devToolKey: $ref: '#/components/schemas/DevToolKeyList' webUrl: type: string description: Canonical Craft.io app URL for this item. Computed in PublishService. type: object description: From T, pick a set of properties whose keys are in the union K ? Omit_Item.workspaceId-or-initiativeId-or-sprint-or-quarter-or-assignee-or-storyPoints-or-estimatedHours-or-objective-or-keyResult-or-persona-or-personas-or-parent-or-labels-or-kano_ : $ref: '#/components/schemas/Pick_Item.Exclude_keyofItem.workspaceId-or-initiativeId-or-sprint-or-quarter-or-assignee-or-storyPoints-or-estimatedHours-or-objective-or-keyResult-or-persona-or-personas-or-parent-or-labels-or-kano__' description: Construct a type with the properties of T except for those in type K. Initiative: $ref: '#/components/schemas/Omit_Item.workspaceId-or-initiativeId-or-sprint-or-quarter-or-assignee-or-storyPoints-or-estimatedHours-or-objective-or-keyResult-or-persona-or-personas-or-parent-or-labels-or-kano_' ItemsPaginated_Initiative_: properties: items: items: $ref: '#/components/schemas/Initiative' type: array metadata: $ref: '#/components/schemas/PaginationMetadata' required: - items - metadata type: object additionalProperties: false EntityId: properties: id: type: string type: object additionalProperties: false NullableType_EntityId_: allOf: - $ref: '#/components/schemas/EntityId' nullable: true NullableType_EntityId-Array_: items: $ref: '#/components/schemas/EntityId' type: array nullable: true ItemCreate: properties: type: type: string workspaceId: type: string title: type: string parent: $ref: '#/components/schemas/NullableType_EntityId_' description: type: string nullable: true storyPoints: type: number format: double initiativeId: $ref: '#/components/schemas/NullableType_string_' value: type: number format: double effort: type: number format: double kano: type: string estimatedHours: type: number format: double labels: items: type: string type: array actualStartDate: $ref: '#/components/schemas/NullableType_Date_' actualEndDate: $ref: '#/components/schemas/NullableType_Date_' status: $ref: '#/components/schemas/NullableType_EntityId_' importance: $ref: '#/components/schemas/NullableType_EntityId_' objectives: $ref: '#/components/schemas/NullableType_EntityId-Array_' keyResults: $ref: '#/components/schemas/NullableType_EntityId-Array_' persona: $ref: '#/components/schemas/NullableType_EntityId_' personas: $ref: '#/components/schemas/NullableType_EntityId-Array_' sprint: $ref: '#/components/schemas/NullableType_EntityId_' quarter: $ref: '#/components/schemas/NullableType_EntityId_' assignee: $ref: '#/components/schemas/NullableType_Assignee_' customFields: items: $ref: '#/components/schemas/CustomFieldValue' type: array outIn: $ref: '#/components/schemas/OutIn' required: - type - workspaceId - title - parent type: object additionalProperties: false ValidateErrorJSON: properties: message: type: string details: properties: {} additionalProperties: {} type: object required: - message - details type: object additionalProperties: false ItemUpdate: properties: id: type: string title: type: string parent: $ref: '#/components/schemas/NullableType_EntityId_' description: type: string nullable: true storyPoints: type: number format: double initiativeId: $ref: '#/components/schemas/NullableType_string_' value: type: number format: double effort: type: number format: double kano: type: string estimatedHours: type: number format: double labels: items: type: string type: array actualStartDate: $ref: '#/components/schemas/NullableType_Date_' actualEndDate: $ref: '#/components/schemas/NullableType_Date_' status: $ref: '#/components/schemas/NullableType_EntityId_' importance: $ref: '#/components/schemas/NullableType_EntityId_' objectives: $ref: '#/components/schemas/NullableType_EntityId-Array_' keyResults: $ref: '#/components/schemas/NullableType_EntityId-Array_' persona: $ref: '#/components/schemas/NullableType_EntityId_' personas: $ref: '#/components/schemas/NullableType_EntityId-Array_' sprint: $ref: '#/components/schemas/NullableType_EntityId_' quarter: $ref: '#/components/schemas/NullableType_EntityId_' assignee: $ref: '#/components/schemas/NullableType_Assignee_' customFields: items: $ref: '#/components/schemas/CustomFieldValue' type: array outIn: $ref: '#/components/schemas/OutIn' required: - id type: object additionalProperties: false FeedbackPortal: properties: id: type: string name: type: string nullable: true url: type: string workspaces: items: $ref: '#/components/schemas/Workspace' type: array webUrl: type: string description: Fully-qualified portal URL (https://{slug}.{FPURL}). Convenience over `url`. type: object additionalProperties: false PortalImportance: properties: id: type: string name: type: string isDefault: type: boolean description: True when this importance is the portal's default — used by create_feedback when `importanceId` is omitted. required: - id - name type: object additionalProperties: false Category: properties: id: type: string name: type: string required: - id - name type: object additionalProperties: false Person: properties: id: type: string name: type: string nullable: true email: type: string type: object additionalProperties: false LinkedItem: properties: id: type: string shortId: type: string title: type: string webUrl: type: string description: Direct link to the linked work item in the Craft.io app. type: object additionalProperties: false NullableType_LinkedItem-Array_: items: $ref: '#/components/schemas/LinkedItem' type: array nullable: true BaseFeedbackItem: properties: id: type: string portalId: type: string shortId: type: string title: type: string description: type: string creationTime: type: string format: date-time category: $ref: '#/components/schemas/Category' owner: $ref: '#/components/schemas/Person' createdBy: $ref: '#/components/schemas/Person' status: $ref: '#/components/schemas/Entity' internalStatus: $ref: '#/components/schemas/Entity' importance: $ref: '#/components/schemas/Entity' labels: items: type: string type: array customFields: items: $ref: '#/components/schemas/CustomFieldValue' type: array linkedItems: $ref: '#/components/schemas/NullableType_LinkedItem-Array_' webUrl: type: string description: Direct link into the feedback portal for this feedback item. required: - id type: object additionalProperties: false FeedbackItem: $ref: '#/components/schemas/BaseFeedbackItem' FeedbackItemsPaginated_FeedbackItem_: properties: items: items: $ref: '#/components/schemas/FeedbackItem' type: array metadata: $ref: '#/components/schemas/PaginationMetadata' required: - items - metadata type: object additionalProperties: false PlainIdeaRequest: properties: workspaceId: type: string title: type: string description: type: string owner: type: string description: "Email address of the idea author. The backend looks up (or\ \ creates) the\r\nperson record from this email and attributes the feedback\ \ to them. This\r\nis NOT a user ID — sending a numeric ID will return\ \ 400." example: user@example.com categoryId: type: string labels: items: type: string type: array importanceId: type: string description: "Portal importance — numeric ID OR exact name (case-insensitive).\ \ When\r\nomitted, the portal's `isDefault: true` importance is used (see\r\ \n`GET /feedback_portal/{portalId}/importances`)." example: Critical required: - title type: object additionalProperties: false IdeaRequest: properties: workspaceId: type: string title: type: string description: type: string owner: type: string description: "Email address of the idea author. The backend looks up (or\ \ creates) the\r\nperson record from this email and attributes the feedback\ \ to them. This\r\nis NOT a user ID — sending a numeric ID will return\ \ 400." example: user@example.com categoryId: type: string labels: items: type: string type: array importanceId: type: string description: "Portal importance — numeric ID OR exact name (case-insensitive).\ \ When\r\nomitted, the portal's `isDefault: true` importance is used (see\r\ \n`GET /feedback_portal/{portalId}/importances`)." example: Critical customFields: items: $ref: '#/components/schemas/CustomFieldValue' type: array required: - title type: object additionalProperties: false FormCustomField: properties: id: type: string name: type: string type: type: string values: items: type: string type: array options: items: $ref: '#/components/schemas/CustomFieldOption' type: array optionShape: $ref: '#/components/schemas/OptionShape' required: type: boolean required: - id - name - type - required type: object additionalProperties: false PortalForm: properties: id: type: string name: type: string categories: items: $ref: '#/components/schemas/Entity' type: array fields: items: $ref: '#/components/schemas/FormCustomField' type: array required: - id - name - categories - fields type: object additionalProperties: false securitySchemes: api_key: type: apiKey in: header name: x-api-key tags: - name: Portfolios description: ''