openapi: 3.0.0
info:
  title: Budget adjustments (beta)
  version: 0.1.0
  description:
    $ref: './md-partials/adjustments-intro.mdx'
servers:
  - url: "https://app.nobl9.com/api/budgetadjustments/v1"
  - url: "https://us1.nobl9.com/api/budgetadjustments/v1"
tags:
  - name: Budget adjustments
    description: >- 
      A budget adjustment event represents a single occurrence of a budget adjustment applied to an SLO based on a predefined budget adjustment definition for the <code>BudgetAdjustment</code> kind in YAML.
      <p/>
      <div class='api-note'><b>AUTHENTICATION REQUIRED</b><br/>Authenticate API requests using an [access token](/api/access-token/generate-access-token). Include it in the Authorization header as <code>Bearer TOKEN</code>.</div>
paths:
  /{adjustmentName}/events:
    get:
      summary: Get a list of budget adjustment events
      description: >-
        Returns a list of [past and ongoing adjustment events](/features/budget-adjustments/#limits-for-budget-adjustments) and the impacted SLOs for a specified adjustment definition.
        <hr/>
        <br/>
        <div class='api-note'><b>LIMITATIONS</b><br/>
        The <code>/{adjustmentName}/events</code> endpoint can return a maximum of 500 events.</div>
        You can optionally filter for a specific SLO (only one). If an SLO is defined, only events for that SLO will be returned, but the results will also include other SLOs associated with those events.
        <br/>
        The results are sorted by event start time.<br/>
        Learn more about [editing budget adjustments](/features/budget-adjustments/#editing-budget-adjustments).
        <p/>
        <div class='api-note'><b>AUTHENTICATION REQUIRED</b><br/>Authenticate API requests using an [access token](/api/access-token/generate-access-token). Include it in the Authorization header as <code>Bearer TOKEN</code>.</div>
      tags:
        - Budget adjustments
      security:
        - bearerAuth: [ admin ]
      parameters:
        - $ref: '#/components/parameters/organization'
        - $ref: '#/components/parameters/adjustmentName'
        - in: query
          name: from
          required: true
          example: 2024-01-25T23:00:00Z
          description:
            Specifies the start date and time for the data range (in UTC).
          schema:
            type: string
            format: date-time
        - in: query
          name: to
          required: true
          example: 2024-01-25T23:59:00Z
          description:
            Specifies the end date and time for the data range (in UTC).<br/>
            <b>This date must be in the past.</b>
          schema:
            type: string
            format: date-time
        - in: query
          name: sloProject
          description: The name of the project holding the provided SLO. Required when <code>sloName</code> is defined.
          required: false
          schema:
            type: string
        - in: query
          name: sloName
          description: The name of the SLO to return. Required when <code>sloProject</code> is defined.
          required: false
          schema:
            type: string
            maxLength: 63
      responses:
        200:
          description: Success
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Event'
              examples:
                objectExample:
                  $ref: '#/components/examples/objectExample'
        400:
          $ref: '#/components/responses/FiltersError'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        404:
          $ref: '#/components/responses/AdjustmentNotFoundError'
  /{adjustmentName}/events/update:
    put:
      summary: Update adjustment events
      description: >-
       Updates existing adjustment events.
       <hr/> 
       Values for <code>eventStart</code> and <code>eventEnd</code> are required.<br/><br/>
       <div class='api-note'><b>LIMITATIONS</b><br/>Budget adjustment recalculations can be run for events from the past 30 days.</div>
        <p/>
        <div class='api-note'><b>AUTHENTICATION REQUIRED</b><br/>Authenticate API requests using an [access token](/api/access-token/generate-access-token). Include it in the Authorization header as <code>Bearer TOKEN</code>.</div>
      tags:
        - Budget adjustments
      security:
        - bearerAuth: [ admin ]
      parameters:
        - $ref: '#/components/parameters/organization'
        - $ref: '#/components/parameters/adjustmentName'
      requestBody:
        description: Optional description in *Markdown*
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/EventUpdate'
      responses:
        202:
          description: Success
        400:
          $ref: '#/components/responses/EventsError'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        404:
          $ref: '#/components/responses/AdjustmentNotFoundError'
  /{adjustmentName}/events/delete:
    post:
      summary: Delete adjustment events
      description: >-
        Deletes existing adjustment events.
        <hr/>
        All specified events and their associated SLOs must exist.
        If any event or The SLO does not exist, none will be deleted, and an error will be returned.<br/><br/>
        <div class='api-note'><b>NOTE</b><br/>Budget adjustment recalculations can be run for events from the past 30 days.</div>
        <p/>
        <div class='api-note'><b>AUTHENTICATION REQUIRED</b><br/>Authenticate API requests using an [access token](/api/access-token/generate-access-token). Include it in the Authorization header as <code>Bearer TOKEN</code>.</div>
      tags:
        - Budget adjustments
      security:
        - bearerAuth: [ admin ]
      parameters:
        - $ref: '#/components/parameters/organization'
        - $ref: '#/components/parameters/adjustmentName'
      requestBody:
        description: Optional description in *Markdown*
        required: true
        content:
          application/json:
            schema:
              type: array
              items:
                $ref: '#/components/schemas/Event'
      responses:
        202:
          description: Success
        400:
          $ref: '#/components/responses/EventsError'
        401:
          $ref: '#/components/responses/UnauthorizedError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        404:
          $ref: '#/components/responses/AdjustmentNotFoundError'
components:
  parameters:
    organization:
      in: header
      name: Organization
      description: ID of your organization.
      required: true
      schema:
        type: string
    adjustmentName:
      in: path
      name: adjustmentName
      description: The name of the adjustment.
      required: true
      schema:
        type: string
  schemas:
    AccessToken:
      properties:
        access_token:
          type: string
      type: object
    Error:
      type: object
      description: >-
        The error object always includes a message and may contain additional fields with further details about the issue.
      additionalProperties: true
      properties:
        title:
          type: string
        source:
              type: array
              items:
                type: object
                properties:
                  propertyName:
                    type: string
                  propertyValue:
                    type: string
      required:
        - title
    Errors:
      type: object
      properties:
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
      additionalProperties: true
    Event:
      type: object
      properties:
        slos:
          type: array
          items:
            $ref: '#/components/schemas/SLO'
          example:
            - project: first-sample-project
              name: first-sample-slo-name
            - project: second-sample-project
              name: second-sample-slo-name
        eventStart:
          type: string
          format: date-time
          example: 2024-06-05T13:00:00Z
        eventEnd:
          type: string
          format: date-time
          example: 2024-06-05T13:00:00Z
    SLO:
      type: object
      properties:
        project:
          type: string
          example: sample-project
        name:
          type: string
          example: sample-slo-name
    EventUpdate:
      type: object
      allOf:
        - $ref: "#/components/schemas/Event"
      properties:
        update:
          type: object
          description: Properties that will be updated.
          properties:
            eventStart:
              type: string
              description: Updated value for the <code>eventStart</code> date.
              format: date-time
              example: 2024-06-05T13:00:00Z
              required: true
            eventEnd:
              type: string
              description: Updated value for the <code>eventEnd</code> date.
              format: date-time
              example: 2024-06-05T13:00:00Z
              required: true
  examples:
    objectExample:
      value:
        - slos:
            - project: first-sample-project
              name: first-sample-slo-name
            - project: second-sample-project
              name: second-sample-slo-name
          eventStart: '2024-06-05T13:00:00Z'
          eventEnd: '2024-06-05T14:00:00Z'
        - slos:
            - project: third-sample-project
              name: third-sample-slo-name
          eventStart: '2024-06-05T18:00:00Z'
          eventEnd: '2024-06-05T19:00:00Z'
      summary: A sample object
  responses:
    BadRequestError:
      description: Bad request
    NotFoundError:
      description: One of the resources referenced in query or payload was not found
    InternalServerError:
      description: Internal server error
    TooManyRequestsError:
      description: API call exceeded the rate limit
    AdjustmentNotFoundError:
      description: The adjustment referenced in the query was not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Errors'
          examples:
            objectExample:
              value:
                errors:
                  - title: "Adjustment '{adjustmentName}' was not found"
    FiltersError:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Errors'
          examples:
            One:
              value:
                errors:
                - source:
                    propertyName: 'from'
                    propertyValue: 2024-06-05 14:00:00 +0000 UTC
                  title: "'To' date must be after 'From' date"
                - source:
                    propertyName: 'to'
                    propertyValue: 2024-06-05 14:00:00 +0000 UTC
                  title: "'To' date must be after 'From' date"
    EventsError:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Errors'
          examples:
            One:
              value:
                errors:
                - source:
                    propertyName: '[3].slos[0].slo'
                    propertyValue: '{"project":"first-sample-project","name":"not-existing-slo"}'
                  title: The SLO does not exist
                  code: slo_does_not_exist
            Multiple:
              value:
                errors:
                - source:
                    propertyName: '[1].slos[1].slo'
                    propertyValue: '{"project":"first-sample-project","name":"not-existing-slo"}'
                  title: The SLO does not exist
                  code: slo_does_not_exist
                - source:
                    propertyName: '[3].event'
                    propertyValue: '{"eventStart":"1970-01-01T00:00:00Z","eventEnd":"1970-01-01T00:00:00Z","slos":[{"project":"first-sam...'
                  title: The SLO does not exist
                  code: slo_does_not_exist
                - source:
                    propertyName: '[2].eventEnd'
                    propertyValue: 2024-06-05 14:00:00 +0000 UTC
                  title: The date cannot be older than 60 days
                - source:
                    propertyName: '[2].eventEnd'
                    propertyValue: 2024-06-05 14:00:00 +0000 UTC
                  title: 'End date must be after Start date'
    UnauthorizedError:
      description: Unauthorized
      headers:
        WWW-Authenticate:
          schema:
            type: string
            description: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Errors'
          examples:
            objectExample:
              value:
                errors:
                  - title: "Unauthorized"
    ForbiddenError:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Errors'
          examples:
            objectExample:
              value:
                errors:
                  - title: "Unauthorized"
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
