openapi: 3.0.3
info:
  title: Control Plane API
  description: |
    <a href="/openapi/ui/control-plane-openapi.yaml" target="_blank" download="control-plane-openapi.yaml"><button>Download OpenAPI Specification</button></a>

    The **Control Plane API** is a set of endpoints for managing the registration of Technology Adapters, generating descriptors from uploaded archives, and starting and monitoring template instantiations.

    # Base URL

    The Witboost URL is the instance URL that you visit in the browser to access the Witboost UI. Therefore, the base URL of the API will depend on your deployment. Below, we are providing an example base URL, yours may differ.
  version: '1.0.0'
tags:
  - name: Builder
    description: Endpoints for managing the registration of Technology Adapters, generating descriptors from uploaded archives, and starting and monitoring template instantiations.
  - name: Hooks
    description: Endpoint for updating the status of a hook, which is used to model third-party approval workflows in Witboost, such as Access Control requests.
servers:
  - url: https://{witboostInstance}
    description: Witboost URL
    variables:
      witboostInstance:
        description: Instance URL that you visit in the browser to access the Witboost UI

paths:
  /register:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    post:
      tags:
        - Builder
      summary: Register a Tech Adapter
      description: |
        This endpoint is used to register the Technology Adapter's URL and link it to the `infrastructureTemplateId`.

        After deploying a new Technology Adapter into the infrastructure, all the components with a your chosen `infrastructureTemplateId` should invoke said microservice. 

        To do so, we need to link the `infrastructureTemplateId` with the Technology Adapter's URL where the microservice is located. Make sure the URL is reachable by the Witboost platform.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - id
                - name
                - description
                - version
                - url
                - environment
              properties:
                id:
                  type: string
                  description: Unique identifier of the Technology Adapter, in the form of a Witboost's URN, like "urn:dmb:itm:snowflake-outputport-provisioner:0"
                name:
                  type: string
                  description: Name of the Technology Adapter, like "Snowflake Output Port"
                description:
                  type: string
                  description: A description that explains the purpose of the Technology Adapter
                version:
                  type: string
                  description: The Technology Adapter's version, like "0". This version must be ALWAYS equal to the version defined in the URN identifier (the last section of the URN identifier after the last ":")
                url:
                  type: string
                  description: The URL of the Technology Adapter, like "http://my-tech-adapter:8093/snowflake-outputport-provisioner". This URL must be reachable from the provisioning coordinator (from a pod in the Kubernetes cluster where the provisioning coordinator is running)
                environment:
                  type: string
                  description: The environment where the Technology Adapter is running, like "production". The environment here must be one of the environments configured for the Builder module of Witboost.
                properties:
                  $ref: '#/components/schemas/InfraTemplateProperties'
            examples:
              snowflakeOutputPort:
                summary: Snowflake Output Port
                value:
                  id: 'urn:dmb:itm:snowflake-outputport-provisioner:0'
                  name: 'Snowflake Output Port'
                  description: 'Provisions a Snowflake Output Port'
                  version: '0'
                  url: 'http://my-tech-adapter:8093/snowflake-outputport-provisioner'
                  environment: 'production'
              guardianTemplate:
                summary: Data Contract Guardian
                value:
                  id: 'urn:dmb:itm:guardian-template:0'
                  name: 'Guardian Template'
                  description: 'Provisions a data contract guardian'
                  version: '0'
                  url: 'http://my-tech-adapter:8093/guardian-provisioner'
                  environment: 'production'
                  properties:
                    dataContractGuardian:
                      policies:
                        - resourceType: dataproduct
                          spec:
                            id: my-guardian-policy-id
                        - resourceType: biproject
                          spec:
                            name: My Guardian Policy
                            description: Policy to collect data contract monitoring results
      responses:
        200:
          description: The Technology Adapter has been registered correctly
          content:
            application/json:
              schema:
                type: string
                description: Contains the result, if no problems are detected, the result will be "OK"
                example: OK
        500:
          description: An error occurred while registering the Technology Adapter
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                error:
                  value:
                    error:
                      message: 'An error occurred while registering the Technology Adapter'

  /v1/entities/descriptor/from-files/info:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    get:
      tags:
        - Builder
      summary: Get descriptor files info
      description: |
        Returns the list of files/folders expected by the descriptor generation flow.
      operationId: getDescriptorFilesInfo
      responses:
        200:
          description: Descriptor files info retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetDescriptorInfoFromFilesResponse'
              examples:
                success:
                  value:
                    files:
                      - catalog-info.yaml
                      - environments
                      - parameters.yaml
        500:
          description: An error occurred while getting info from descriptor files
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                error:
                  value:
                    error:
                      message: 'Error while getting info from descriptor files.'

  /v1/entities/descriptor/from-files:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    post:
      tags:
        - Builder
      summary: Build descriptor from files archive
      description: |
        Builds a single descriptor by processing an uploaded archive containing one or more entity directories.

        The archive must be in `.tar.gz` or `.tgz` format. Each top-level directory in the archive represents one entity and must include a `catalog-info.yaml` file. It can also optionally include:
        - `parameters.yaml`
        - `environments/<environment>/configurations.yaml`

        The processing flow unpacks all directories, resolves each entity's descriptor from its `catalog-info.yaml`, distinguishes between system and component descriptors, then merges all component descriptors into the system descriptor, which acts as the root.

        **Note:** The archive is expected to contain exactly one system directory. If multiple system directories are present, only the first one will be used and the others will be ignored.
      operationId: buildDescriptorFromFiles
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/BuildDescriptorFromFilesRequest'
            encoding:
              archive:
                contentType: application/gzip
            examples:
              minimal:
                value:
                  environment: development
      responses:
        200:
          description: Descriptor built successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BuildDescriptorFromFilesResponse'
              examples:
                success:
                  value:
                    descriptor:
                      projectKind: system
                      dataProductOwner: group:default/data-team
                      domain: finance
                      kind: System
                      metadata:
                        name: my-data-product
        400:
          description: Invalid form data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
              examples:
                invalidBody:
                  value:
                    errors:
                      - Invalid form data: missing archive or environment
                    moreInfo:
                      problems:
                        - '{"code":"invalid_type","path":["archive"],"message":"Required"}'
                      solutions: []
        500:
          description: An error occurred while building descriptor from files
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                error:
                  value:
                    error:
                      message: 'Error while building descriptor from files.'

  /v1/templates/instantiation:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    post:
      tags:
        - Builder
      summary: Instantiate a template
      description: |
        Starts a new template instantiation asynchronously. The endpoint returns the created task identifier. 

        See the [Template page](/docs/data-teams/p6_advanced/p6_1_templates#how-to-instantiate-a-template-programmatically) for a step-by-step guide.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InstantiateTemplateRequest'
            examples:
              minimal:
                value:
                  templateRef: 'template:default/my-data-product-template'
                  values:
                    name: 'my-data-product'
                    owner: 'group:default/data-team'
              withEnvironmentParameters:
                value:
                  templateRef: 'template:default/my-template'
                  values:
                    name: 'my-data-product'
                  environmentParameters:
                    development:
                      region: 'eu-west-1'
                    production:
                      region: 'eu-central-1'
      responses:
        200:
          description: Template instantiation started successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InstantiateTemplateResponse'
              examples:
                success:
                  value:
                    id: '2f4b7a6f-6d2e-4a22-a912-cce8f90b3843'
        400:
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                invalidBody:
                  value:
                    error:
                      message: 'Invalid request body: missing template reference or values'
        500:
          description: An error occurred while instantiating the template
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                error:
                  value:
                    error:
                      message: 'Error while instantiating template.'

  /v1/templates/instantiation/{taskId}/stream:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    get:
      tags:
        - Builder
      summary: Stream template instatiation events
      description: |
        Opens a Server-Sent Events (SSE) stream for a template instantiation task.

        Events are emitted as `event: <type>` and `data: <json>` records. Supported event types include
        `log`, `recovered`, `cancelled`, and `completion`.

        See the [Template page](/docs/data-teams/p6_advanced/p6_1_templates#how-to-instantiate-a-template-programmatically) for a step-by-step guide.
      parameters:
        - in: path
          name: taskId
          required: true
          description: The template instantiation task identifier
          schema:
            type: string
      responses:
        200:
          description: SSE stream opened successfully
          content:
            text/event-stream:
              schema:
                type: string
                description: Server-Sent Events stream payload
              examples:
                logEvent:
                  value: |
                    event: log
                    data: {"message":"Starting template execution","createdAt":"2026-01-01T10:00:00.000Z"}

                    event: completion
                    data: {"message":"Task completed","createdAt":"2026-01-01T10:00:10.000Z"}
        500:
          description: An error occurred while streaming template instantiation logs
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                error:
                  value:
                    error:
                      message: 'An error occurred while streaming template instantiation logs.'

  /v1/templates/instantiation/{taskId}/status:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    get:
      tags:
        - Builder
      summary: Get template instantiation status
      description: |
        Returns the latest status for a template instantiation task.

        See the [Template page](/docs/data-teams/p6_advanced/p6_1_templates#how-to-instantiate-a-template-programmatically) for a step-by-step guide.
      parameters:
        - in: path
          name: taskId
          required: true
          description: The template instantiation task identifier
          schema:
            type: string
      responses:
        200:
          description: Task status retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/GetTemplateInstantiationStatusResponse'
              examples:
                open:
                  value:
                    status: 'open'
                completed:
                  value:
                    status: 'completed'
        500:
          description: An error occurred while getting template instantiation status
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                error:
                  value:
                    error:
                      message: 'Error while getting template instantiation status.'

  /hooks/{id}:
    servers:
      - url: https://{witboostInstance}/api/actionHandler
        description: Witboost URL for Hooks API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    patch:
      tags:
        - Hooks
      summary: Update the status of a hook
      description: |
        Witboost Hooks model third-party approval workflows. 

        Hooks are used, for instance, to model the Access Control workflow, where an Data Consumer asks access to a Data Owner.
        In case an Access Control request is forwarded to third-party ticketing systems, this endpoint helps Witboost understand whether the request is still pending, completed or rejected/failed.  

        In general, outside of the Access Control workflow, this endpoint is used to update the status of a hook, so that the Witboost platform knows how to proceed with a pending request.
      parameters:
        - in: path
          name: id
          schema:
            type: string
          required: true
          description: |
            Request ID as provided by the Witboost platform in the respondToUrl field.
      requestBody:
        description: A resource to be evaluated
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/UpdateHookRequest'
                - $ref: '#/components/schemas/TraceableUpdateHookRequest'
            examples:
              accept:
                value:
                  status: OK
                  hookInfo:
                    message: 'The request has been accepted on the external system'
              reject:
                value:
                  status: KO
                  hookInfo:
                    message: 'The request has been rejected on the external system'
              acceptWithTracking:
                value:
                  status: OK
                  hookInfo:
                    message: 'The request has been accepted on the external system'
                    tracking:
                      id: '123456'
                      url: 'https://external-system.com/requests/123456'

        required: true
      responses:
        200:
          description: The hook has been updated correctly
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateHookResponse'
              examples:
                accepted:
                  value:
                    hookId: '34797dd1-1f25-48b0-89c7-14d2ce04a78b'
                    hookName: 'RemoteRequestHook'
                    actionId: '0298b78f-4d77-45f7-a7a4-f16278144141'
                    actionName: 'AccessControlAction'
                    creationAt: '2021-09-01T12:00:00Z'
                    updateAt: '2021-09-01T12:00:00Z'
                    status: OK
                rejected:
                  value:
                    hookId: '34797dd1-1f25-48b0-89c7-14d2ce04a78b'
                    hookName: 'RemoteRequestHook'
                    actionId: '0298b78f-4d77-45f7-a7a4-f16278144141'
                    actionName: 'AccessControlAction'
                    creationAt: '2021-09-01T12:00:00Z'
                    updateAt: '2021-09-01T12:00:00Z'
                    status: KO
        404:
          description: There is no hook handler or no action handler for the specified hook. This can happen when a action or a hook gets removed from witboost after a deprecation period.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                notFound:
                  value:
                    error:
                      message: 'The hook handler or action handler was not found'
        409:
          description: Hook is in an immutable state. A hook can be updated only if its status is WAITING
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                immutable:
                  value:
                    error:
                      message: 'The hook is in an immutable state'
        500:
          description: System problem
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                error:
                  value:
                    error:
                      message: 'An error occurred while updating the hook'

  /v1/feature-requests:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    post:
      tags:
        - Builder
      summary: Create a Feature Request
      description: |
        Submits a new Feature Request against a System or a specific Component.

        Requires the `control-plane.feature-request.create` RBAC permission scoped to the target System's URN.
        Accepts `multipart/form-data` to support binary file attachments (PDF, JPG, PNG; max 5 files, 10 MB each).

        Both `projectUrn` and `componentUrn` (when provided) are validated:
        - **Format**: must be a valid Witboost URN (`urn:dmb:<kind>:<domain>:<name>:<version>[:<component>[:<subcomponent>]]`).
        - **Existence**: the referenced entity must exist in the Witboost catalog.
        - **Hierarchy** (componentUrn only): the component must belong to the system identified by `projectUrn`.
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - summary
                - description
                - priority
                - projectUrn
              properties:
                summary:
                  type: string
                  maxLength: 500
                  description: Short title describing the request
                description:
                  type: string
                  maxLength: 10000
                  description: Detailed description of the requested feature or improvement
                priority:
                  type: string
                  enum: [LOW, MEDIUM, HIGH, CRITICAL]
                  description: Caller-assigned priority level
                projectUrn:
                  type: string
                  description: |
                    URN of the target System. Must be a valid Witboost URN referencing an existing entity in the catalog.
                    Format: `urn:dmb:<kind>:<domain>:<name>:<version>`
                  example: 'urn:dmb:dp:finance:cashflow:0'
                componentUrn:
                  type: string
                  description: |
                    URN of the target Component (optional). When provided, must be a valid Witboost URN referencing an existing component that belongs to the system identified by `projectUrn`.
                    Format: `urn:dmb:cmp:<domain>:<name>:<version>:<component>`
                  example: 'urn:dmb:cmp:finance:cashflow:0:storage'
                attachments:
                  anyOf:
                    - type: string
                      format: binary
                    - type: array
                      items:
                        type: string
                        format: binary
                  description: Binary file uploads. Only PDF, JPG, and PNG allowed. Max 5 files, 10 MB each.
      responses:
        '201':
          description: Feature Request created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeatureRequestDetail'
              examples:
                created:
                  value:
                    id: 'aaaaaaaa-0000-0000-0000-000000000001'
                    summary: 'Add export feature'
                    description: 'Allow users to export data as CSV'
                    status: 'SUBMITTED'
                    priority: 'MEDIUM'
                    projectUrn: 'urn:dmb:dp:finance:cashflow:0'
                    componentUrn: null
                    requesterRef: 'user:default/alice'
                    createdAt: '2026-06-01T10:00:00.000Z'
                    createdBy: 'user:default/alice'
                    updatedAt: '2026-06-01T10:00:00.000Z'
                    updatedBy: 'user:default/alice'
                    attachments: []
        '400':
          description: Invalid input — malformed URN, non-existent entity, or component not belonging to the target system
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                malformedUrn:
                  summary: Malformed URN
                  value:
                    error:
                      message: "Invalid projectUrn: Malformed URN received: 'not-a-urn'. Must be a valid Witboost URN (e.g., 'urn:dmb:dp:domain:name:version')"
                entityNotFound:
                  summary: Entity not found in catalog
                  value:
                    error:
                      message: "Invalid projectUrn: entity not found in catalog for URN 'urn:dmb:dp:finance:nonexistent:0'"
                hierarchyMismatch:
                  summary: Component does not belong to the target system
                  value:
                    error:
                      message: "Invalid componentUrn: component 'urn:dmb:cmp:finance:cashflow:0:storage' does not belong to the system identified by projectUrn 'urn:dmb:dp:other:system:0'"
        '401':
          description: Unauthorized — no valid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                unauthorized:
                  value:
                    error:
                      message: 'Unauthorized'
        '403':
          description: Forbidden — caller lacks the `control-plane.feature-request.create` permission
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                forbidden:
                  value:
                    error:
                      message: "Forbidden: missing 'control-plane.feature-request.create' permission"

  /v1/feature-requests/by-project:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    get:
      tags:
        - Builder
      summary: List Feature Requests for a System
      description: |
        Returns a paginated list of Feature Requests for the specified System.

        The caller must be the **Data Product Owner** (or owner delegate) of the System, resolved via Team Roles.
        Service principals bypass the ownership check.

        The `projectUrn` query parameter is **required** and must be a valid Witboost URN.
        Optional filters (`componentUrn`, `status`, `priority`) and pagination (`offset`, `limit`) are supported.
      parameters:
        - in: query
          name: projectUrn
          required: true
          schema:
            type: string
          description: |
            URN of the System. Must be a valid Witboost URN.
            Format: `urn:dmb:<kind>:<domain>:<name>:<version>`
          example: 'urn:dmb:dp:finance:cashflow:0'
        - in: query
          name: componentUrn
          required: false
          schema:
            type: string
          description: |
            Narrow results to requests targeting a specific Component.
            Must be a valid Witboost URN when provided.
            Format: `urn:dmb:cmp:<domain>:<name>:<version>:<component>`
          example: 'urn:dmb:cmp:finance:cashflow:0:storage'
        - in: query
          name: status
          required: false
          schema:
            type: string
            enum: [SUBMITTED, APPROVED, IN_PROGRESS, IMPLEMENTED, REJECTED]
          description: Filter by status
        - in: query
          name: priority
          required: false
          schema:
            type: string
            enum: [LOW, MEDIUM, HIGH, CRITICAL]
          description: Filter by priority
        - in: query
          name: offset
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
          description: Pagination offset (zero-based)
        - in: query
          name: limit
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          description: Page size (1–100)
      responses:
        '200':
          description: Paginated list of Feature Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedFeatureRequests'
              examples:
                list:
                  value:
                    items:
                      - id: 'aaaaaaaa-0000-0000-0000-000000000001'
                        summary: 'Add export feature'
                        status: 'SUBMITTED'
                        priority: 'MEDIUM'
                        projectUrn: 'urn:dmb:dp:finance:cashflow:0'
                        componentUrn: null
                        requesterRef: 'user:default/alice'
                        createdAt: '2026-06-01T10:00:00.000Z'
                        createdBy: 'user:default/alice'
                        updatedAt: '2026-06-01T10:00:00.000Z'
                        updatedBy: 'user:default/alice'
                    total: 1
                    offset: 0
                    limit: 20
        '400':
          description: Missing or invalid `projectUrn`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                malformedUrn:
                  value:
                    error:
                      message: 'Invalid request parameters'
        '401':
          description: Unauthorized — no valid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — caller is not the owner of the specified System
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                forbidden:
                  value:
                    error:
                      message: 'Forbidden: only project owners can list Feature Requests by project'

  /v1/feature-requests/by-requester:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    get:
      tags:
        - Builder
      summary: List Feature Requests submitted by the authenticated caller
      description: |
        Returns a paginated list of Feature Requests submitted by the currently authenticated user.

        Results are implicitly scoped to the caller's identity — no additional authorization is required beyond a valid session.
        Optional filters (`projectUrn`, `status`, `priority`) and pagination (`offset`, `limit`) are supported.
      parameters:
        - in: query
          name: projectUrn
          required: false
          schema:
            type: string
          description: Filter by System URN
          example: 'urn:dmb:dp:finance:cashflow:0'
        - in: query
          name: status
          required: false
          schema:
            type: string
            enum: [SUBMITTED, APPROVED, IN_PROGRESS, IMPLEMENTED, REJECTED]
          description: Filter by status
        - in: query
          name: priority
          required: false
          schema:
            type: string
            enum: [LOW, MEDIUM, HIGH, CRITICAL]
          description: Filter by priority
        - in: query
          name: offset
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
          description: Pagination offset (zero-based)
        - in: query
          name: limit
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          description: Page size (1–100)
      responses:
        '200':
          description: Paginated list of Feature Requests submitted by the caller
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaginatedFeatureRequests'
        '400':
          description: Invalid filter values
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized — no valid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /v1/feature-requests/{id}:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    get:
      tags:
        - Builder
      summary: Retrieve full Feature Request details
      description: |
        Returns the full details of a Feature Request including its description and attachment metadata (without binary content).

        Accessible to:
        - The **Data Product Owner** (or owner delegate) of the associated System
        - The **original requester** who submitted the Feature Request
        - Service principals
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: Feature Request ID
      responses:
        '200':
          description: Feature Request details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeatureRequestDetail'
              examples:
                detail:
                  value:
                    id: 'aaaaaaaa-0000-0000-0000-000000000001'
                    summary: 'Add export feature'
                    description: 'Allow users to export data as CSV'
                    status: 'SUBMITTED'
                    priority: 'MEDIUM'
                    projectUrn: 'urn:dmb:dp:finance:cashflow:0'
                    componentUrn: null
                    requesterRef: 'user:default/alice'
                    createdAt: '2026-06-01T10:00:00.000Z'
                    createdBy: 'user:default/alice'
                    updatedAt: '2026-06-01T10:00:00.000Z'
                    updatedBy: 'user:default/alice'
                    attachments:
                      - id: 'bbbbbbbb-0000-0000-0000-000000000001'
                        filename: 'mockup.png'
                        contentType: 'image/png'
                        size: 204800
        '401':
          description: Unauthorized — no valid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — caller is neither the System owner nor the requester
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                forbidden:
                  value:
                    error:
                      message: 'Forbidden: only project owners or the original requester can view this Feature Request'
        '404':
          description: Feature Request not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      tags:
        - Builder
      summary: Delete a Feature Request
      description: |
        Permanently deletes a Feature Request and all its associated attachments.

        Restricted to the **original requester** who submitted the Feature Request.
        Service principals bypass the ownership check.
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: Feature Request ID
      responses:
        '204':
          description: Feature Request deleted successfully
        '401':
          description: Unauthorized — no valid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — caller is not the original requester
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                forbidden:
                  value:
                    error:
                      message: 'Forbidden: only the original requester can delete a Feature Request'
        '404':
          description: Feature Request not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /v1/feature-requests/{id}/status:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    patch:
      tags:
        - Builder
      summary: Update the status of a Feature Request
      description: |
        Updates the status of a Feature Request to any valid value.
        No transition restrictions are enforced — any status can be set regardless of the current status.

        Restricted to:
        - The **Data Product Owner** (or owner delegate) of the associated System
        - Service principals
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: Feature Request ID
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  enum:
                    [SUBMITTED, APPROVED, IN_PROGRESS, IMPLEMENTED, REJECTED]
                  description: The new status to set
            examples:
              approve:
                summary: Approve a request
                value:
                  status: 'APPROVED'
              reject:
                summary: Reject a request
                value:
                  status: 'REJECTED'
      responses:
        '200':
          description: Updated Feature Request summary (without attachments)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FeatureRequestSummary'
              examples:
                updated:
                  value:
                    id: 'aaaaaaaa-0000-0000-0000-000000000001'
                    summary: 'Add export feature'
                    status: 'APPROVED'
                    priority: 'MEDIUM'
                    projectUrn: 'urn:dmb:dp:finance:cashflow:0'
                    componentUrn: null
                    requesterRef: 'user:default/alice'
                    createdAt: '2026-06-01T10:00:00.000Z'
                    createdBy: 'user:default/alice'
                    updatedAt: '2026-06-03T14:30:00.000Z'
                    updatedBy: 'user:default/owner'
        '400':
          description: Invalid status value
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                invalidStatus:
                  value:
                    error:
                      message: 'Invalid request parameters'
        '401':
          description: Unauthorized — no valid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — caller is not the System owner
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                forbidden:
                  value:
                    error:
                      message: 'Forbidden: only project owners can update Feature Request status'
        '404':
          description: Feature Request not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /v1/feature-requests/{id}/attachments/{attachmentId}/download:
    servers:
      - url: https://{witboostInstance}/api/builder
        description: Witboost URL for Builder API
        variables:
          witboostInstance:
            description: Instance URL that you visit in the browser to access the Witboost UI
    get:
      tags:
        - Builder
      summary: Download a Feature Request attachment
      description: |
        Returns the binary content of a single attachment with the correct `Content-Type` and
        `Content-Disposition` headers set for browser download.

        Accessible to:
        - The **Data Product Owner** (or owner delegate) of the associated System
        - The **original requester** who submitted the Feature Request
        - Service principals
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
            format: uuid
          description: Feature Request ID
        - in: path
          name: attachmentId
          required: true
          schema:
            type: string
            format: uuid
          description: Attachment ID (from the `attachments` array in the Feature Request detail)
      responses:
        '200':
          description: Binary file content
          headers:
            Content-Disposition:
              schema:
                type: string
              description: 'Suggested filename, e.g. `attachment; filename="mockup.png"`'
          content:
            application/pdf:
              schema:
                type: string
                format: binary
            image/jpeg:
              schema:
                type: string
                format: binary
            image/png:
              schema:
                type: string
                format: binary
        '401':
          description: Unauthorized — no valid session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: Forbidden — caller is neither the System owner nor the requester
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                forbidden:
                  value:
                    error:
                      message: 'Forbidden: only project owners or the original requester can download attachments'
        '404':
          description: Feature Request or attachment not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    InfraTemplateProperties:
      type: object
      description: Additional infrastructure template properties
      properties:
        dataContractGuardian:
          $ref: '#/components/schemas/InfraTemplateGuardianProperties'

    InfraTemplateGuardianProperties:
      type: object
      description: When specified during the registration of an infrastructure template, the template will be designated as a data contract guardian template
      required:
        - policies
      properties:
        policies:
          description: >
            List of policies in the Witboost Computational Governance to be associated to the guardian template.
            This list should include **at most one** policy per resource type.
            If the provided list contains fewer policies than those currently associated with the template, 
            the additional policies that are not included in the list will be unlinked from the template. 
            This means that the list you provide represents the target set of policies for the template
          type: array
          items:
            type: object
            required:
              - resourceType
              - spec
            properties:
              resourceType:
                description: >
                  During the provisioning of a data contract guardian linked to this infrastructure template, 
                  the Coordinator will identify the resource type of the deployment unit containing the data contract guardian (as a component),
                  and use it to retrieve the corresponding passive policy that will be provided to the guardian's tech adapter.
                  <br /><br />**Note:** The referenced resource type is that of the deployment unit containing the data contract guardian, 
                  and not the resource type of the guardian itself
                type: string
                example: dataproduct
              spec:
                type: object
                description: >
                  Policy specification. You must provide either:
                    - the `id` of an existing passive policy that is already registered in the Witboost Computational Governance.
                      **Note:** If a policy for the same resource type is already associated with this template, it will be replaced by the provided policy.
                      The previous policy will NOT be removed from the Witboost Computational Governance
                    - OR, `name` and (optionally) `description` for a new passive policy that will be automatically registered in the Witboost Computational Governance.
                      **Note:** If a policy for the same resource type is already associated with this template, this spec will have no effect
                properties:
                  id:
                    description: Id of an existing passive policy (**required** when `name` is not specified)
                    type: string
                    example: 9f86d081-8143-4196-8536-41c91f876f7c
                  name:
                    description: Name of the passive policy (**required** when `id` is not specified)
                    type: string
                    example: Data Contract Guardian Policy
                  description:
                    description: Description of the passive policy
                    type: string
                    example: Passive policy for data contract monitoring results

    GetDescriptorInfoFromFilesResponse:
      type: object
      description: Response containing expected files/folders for descriptor generation
      required:
        - files
      properties:
        files:
          type: array
          items:
            type: string
          description: List of required or supported files/folders

    BuildDescriptorFromFilesRequest:
      type: object
      description: Multipart payload used to generate a descriptor from an archive
      required:
        - archive
        - environment
      properties:
        archive:
          type: string
          format: binary
          description: Archive file containing descriptor source files (`.tar.gz` or `.tgz`)
        environment:
          type: string
          description: Target environment used to resolve environment-specific configurations
          example: development

    BuildDescriptorFromFilesResponse:
      type: object
      description: Resulting descriptor built from uploaded files
      required:
        - descriptor
      properties:
        descriptor:
          type: object
          description: Generated descriptor object
          additionalProperties: true

    ValidationError:
      type: object
      required:
        - errors
      properties:
        errors:
          type: array
          items:
            type: string
          description: User-friendly validation errors
        moreInfo:
          type: object
          additionalProperties: true
          description: Additional diagnostics for troubleshooting input issues

    InstantiateTemplateRequest:
      type: object
      description: Request payload to start a template instantiation task
      required:
        - templateRef
        - values
      properties:
        templateRef:
          type: string
          description: Entity reference of the template to instantiate
          example: template:default/my-template
        values:
          type: object
          description: Input values for template parameters
          additionalProperties: true
        environmentParameters:
          type: object
          description: Optional environment-scoped parameter overrides
          additionalProperties:
            type: object
            additionalProperties: true

    InstantiateTemplateResponse:
      type: object
      description: Response returned after template task creation
      required:
        - id
      properties:
        id:
          type: string
          description: Identifier of the created task
          example: 2f4b7a6f-6d2e-4a22-a912-cce8f90b3843

    GetTemplateInstantiationStatusResponse:
      type: object
      description: Current status of a template instantiation task
      required:
        - status
      properties:
        status:
          type: string
          description: Current task status
          enum:
            - open
            - processing
            - completed
            - failed
            - skipped
          example: processing

    UpdateHookRequest:
      type: object
      description: An update hook request
      required:
        - status
      properties:
        status:
          $ref: '#/components/schemas/RequestedHookState'
        hookInfo:
          type: object
          description: A free-form object that will be stored as the hook's response data

    TraceableUpdateHookRequest:
      type: object
      description: An update hook request with embedded traceable information
      required:
        - status
      properties:
        status:
          $ref: '#/components/schemas/RequestedHookState'
        hookInfo:
          type: object
          description: A free-form object that will be stored as the hook's response data with an optional reserved field name for tracking information
          properties:
            tracking:
              type: object
              description: A reserved field for any available tracking information for the users to check the status of their request in the external system
              properties:
                id:
                  type: string
                  description: An optional id of the request on the external system, this is helpful if the external system is known to witboost and can reconstruct the URL that a user should visit. Or when it's not possible to provide a viewable URL for the user to check the status of the request.
                url:
                  type: string
                  description: An optional URL of the request on the external system, it should link to an external system that can show to the users the status of their requests
          additionalProperties: true

    UpdateHookResponse:
      type: object
      description: Represents the response structure for updating a hook.
      required:
        - hookId
        - hookName
        - creationAt
        - updateAt
        - status
      properties:
        hookId:
          type: string
          description: The unique identifier of the hook.
        hookName:
          type: string
          description: The name of the hook.
        actionId:
          type: string
          description: The unique identifier of the action associated with the hook, if any.
        actionName:
          type: string
          description: The name of the action associated with the hook, if any.
        creationAt:
          type: string
          format: date-time
          description: The timestamp indicating when the hook was created.
        updateAt:
          type: string
          format: date-time
          description: The timestamp indicating the last update time of the hook.
        status:
          $ref: '#/components/schemas/HookState'

    RequestedHookState:
      type: string
      description: Represents the desired state of the hook. OK means the third-party interaction has been completed with a positive result, KO on the other hand can be used to represent a negative result. If the hook is attached to an action, signaling KO could prevent the action's callback to be invoked
      enum:
        - KO
        - OK

    HookState:
      type: string
      description: The current state of the hook, referencing the HookState schema.
      enum:
        - WAITING
        - KO
        - OK

    AttachmentMetadata:
      type: object
      description: Metadata for a file attached to a Feature Request
      required:
        - id
        - filename
        - contentType
        - size
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier of the attachment
        filename:
          type: string
          description: Original file name
        contentType:
          type: string
          description: MIME type of the file (application/pdf, image/jpeg, image/png)
        size:
          type: integer
          description: File size in bytes

    FeatureRequestSummary:
      type: object
      description: Summary representation of a Feature Request
      required:
        - id
        - summary
        - status
        - priority
        - projectUrn
        - requesterRef
        - createdAt
        - createdBy
        - updatedAt
        - updatedBy
      properties:
        id:
          type: string
          format: uuid
        summary:
          type: string
        status:
          type: string
          enum: [SUBMITTED, APPROVED, IN_PROGRESS, IMPLEMENTED, REJECTED]
          description: Current status of the Feature Request
        priority:
          type: string
          enum: [LOW, MEDIUM, HIGH, CRITICAL]
          description: Priority level of the Feature Request
        projectUrn:
          type: string
          description: URN of the target System
        componentUrn:
          type: string
          nullable: true
          description: URN of the target Component, if any
        requesterRef:
          type: string
          description: Backstage entity reference of the requester
        createdAt:
          type: string
          format: date-time
        createdBy:
          type: string
        updatedAt:
          type: string
          format: date-time
        updatedBy:
          type: string

    FeatureRequestDetail:
      description: Full representation of a Feature Request including description and attachments
      allOf:
        - $ref: '#/components/schemas/FeatureRequestSummary'
        - type: object
          required:
            - description
          properties:
            description:
              type: string
              description: Detailed description of the requested feature or improvement
            attachments:
              type: array
              items:
                $ref: '#/components/schemas/AttachmentMetadata'

    PaginatedFeatureRequests:
      type: object
      description: Paginated list of Feature Request summaries
      required:
        - items
        - total
        - offset
        - limit
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/FeatureRequestSummary'
        total:
          type: integer
          description: Total number of matching Feature Requests
        offset:
          type: integer
          description: Current pagination offset
        limit:
          type: integer
          description: Page size used for the query

    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - message
          properties:
            message:
              type: string
              description: An informative user-friendly message that informs about occurred errors
          additionalProperties: true
