openapi: 3.0.0
info:
  title: SLO annotations
  version: v1alpha
  description:
    $ref: './md-partials/annotations-intro.mdx'
servers:
  - url: "https://app.nobl9.com/api"
  - url: "https://us1.nobl9.com/api"
tags:
  - name: SLO annotations
paths:
  /annotations:
    get:
      summary: Get the list of annotations
      tags:
        - SLO annotations
      description: >-
        Retrieves a list of SLO annotations based on specified filter criteria.
        <hr/>
        <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>
      security:
        - bearerAuth: [ ]
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            curl -X \
            GET https://app.nobl9.com/api/annotations?from=2025-08-07T08:00:00Z&to=2025-08-08T13:00:00Z&name=my-annotation-1&name=my-annotation-2&slo=my-slo' -H 'Accept: application/json; version=v1alpha' \
            -H 'Organization: your-organization-id' \
            -H 'Project: *' \
            -H 'Authorization: Bearer ${access_token}'
      parameters:
        - $ref: '#/components/parameters/organization'
        - description: Project name, must conform to DNS (RFC 1123 format). Can be a wildcard with `*`.
          in: header
          name: Project
          required: true
          schema:
            type: string
        - description: The name of the annotation. You can provide multiple names. The query matches all the names.
          explode: false
          in: query
          name: name
          schema:
            items:
              type: string
            type: array
          style: form
        - description: The name of the annotated SLO.
          in: query
          name: slo
          schema:
            type: string
        - description: Matches `Annotation.startTime`. Start time of the annotation period in RFC3339 format.
          in: query
          name: from
          example: 2025-08-07T08:00:00Z
          schema:
            type: string
            format: date-time
        - description: Matches `Annotation.endTime`. End time of the annotation period in RFC3339 format.
          in: query
          name: to
          example: 2025-08-07T09:00:00Z
          schema:
            type: string
            format: date-time
        - description: |
            The type of annotation to filter by. You can provide multiple values. Must be one of:
            * Adjustment—System-generated annotations for budget adjustments
            * Alert—System-generated annotations for SLO alerts
            * NoDataAnomaly—System-generated annotations for no data anomalies
            * User—User-created annotations
          in: query
          name: category
          required: false
          schema:
            type: string
            enum: [Adjustment, Alert, NoDataAnomaly, User]
      responses:
        '200':
          content:
            application/json:
              schema:
                items:
                  $ref: '#/components/schemas/Annotation'
                type: array
          description: Success
        400:
          $ref: '#/components/responses/BadRequestError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        500:
          $ref: '#/components/responses/InternalServerError'
    post:
      summary: Create single annotation
      tags:
        - SLO annotations
      description: >-
        Creates an annotation to mark an event for a specific SLO.
        <hr/>
        <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>
      security:
        - bearerAuth: [ ]
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            curl -X \
            POST https://app.nobl9.com/api/annotations -H 'Accept: application/json; version=v1alpha' \
            -H 'Organization: my-org' \
            -H 'Authorization: Bearer ${access_token}" -d "@create.json'
      parameters:
        - $ref: '#/components/parameters/organization'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnnotationPostPayload'
        description: <b>JSON object keys</b>
        required: true
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Annotation'
          description: Created annotation
        400:
          $ref: '#/components/responses/BadRequestError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        404:
          $ref: '#/components/responses/NotFoundError'
        409:
          description: Annotation already exists
        500:
          $ref: '#/components/responses/InternalServerError'
  /annotations/{name}:
    delete:
      summary: Delete single annotation
      tags:
        - SLO annotations
      description: >-
        Deletes an annotation with the given name in the specified project.
        <hr/>
        <p/>
        <b>Provide a project name explicitly, wildcards are not accepted.</b>
        <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>
        <p/>
        <div class='api-note'><b>RBAC</b><br/> Only *Organization Admins* can delete [system annotations](/features/slo-annotations/#system-annotations), for example, when a false alert was triggered. Users with other permissions can only *view* system annotations.</div>
      security:
        - bearerAuth: [ ]
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            curl -X \
            DELETE https://app.nobl9.com/api/annotations/my-annotation -H 'Accept: application/json; version=v1alpha' \
            -H 'Organization: my-org' \
            -H 'Project: my-project' \
            -H 'Authorization: Bearer ${access_token}'
      parameters:
        - $ref: '#/components/parameters/organization'
        - description: Project name, must be explicit, wildcard is not supported
          in: header
          name: Project
          required: true
          schema:
            type: string
        - description: Annotation name
          in: path
          name: name
          required: true
          schema:
            type: string
      responses:
        204:
          description: Annotation deleted or not found
        400:
          $ref: '#/components/responses/BadRequestError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        500:
          $ref: '#/components/responses/InternalServerError'
    put:
      summary: Upsert single annotation
      tags:
        - SLO annotations
      description: >-
        Update annotations using a standard `PUT` request.
        <hr/>
        This method will create a new annotation unless the annotation with the provided name (i.e. specified in the body of the JSON object) does not exist in the specified project.
        <p/>
        Provide all the remaining parameters even if you want to update just one of them (effectively, this command acts like a `REPLACE` command).
        <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>
      security:
        - bearerAuth: [ ]
      x-codeSamples:
        - lang: Bash
          label: cURL
          source: |
            curl -X \
            PUT https://app.nobl9.com/api/annotations/my-annotation -H 'Accept: application/json; version=v1alpha' \
            -H 'Organization: my-org' \
            -H 'Authorization: Bearer ${access_token}'
      parameters:
        - $ref: '#/components/parameters/organization'
        - description: Annotation name
          in: path
          name: name
          required: true
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AnnotationPutPayload'
        description: Annotations' details
        required: true
      responses:
        200:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Annotation'
          description: Created or replaced annotation
        400:
          $ref: '#/components/responses/BadRequestError'
        403:
          $ref: '#/components/responses/ForbiddenError'
        404:
          $ref: '#/components/responses/NotFoundError'
        500:
          $ref: '#/components/responses/InternalServerError'
components:
  responses:
    BadRequestError:
      description: Bad request
    UnauthorizedError:
      description: Unauthorized
      headers:
        WWW-Authenticate:
          schema:
            type: string
            description: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate'
    ForbiddenError:
      description: Forbidden
    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
  parameters:
    organization:
      in: header
      name: Organization
      description: Your organization ID. You can find it in the Nobl9 web application, under your account settings.
      required: true
      schema:
        type: string
  schemas:
    AccessToken:
      properties:
        access_token:
          type: string
      type: object
    Error:
      type: object
      description: >-
        Error will always contain the status code and message,
        but might also contain additional fields that describe the problem in more details.
      additionalProperties: true
      properties:
        message:
          type: string
        statusCode:
          type: integer
      required:
        - statusCode
        - message
    Annotation:
      properties:
        description:
          type: string
          description: Description of the annotation.
        name:
          example: my-annotation-name
          type: string
          description: The name of the annotation.
        project:
          example: default
          type: string
          description: Must conform to DNS (RFC 1123 format).
        slo:
          example: my-slo-name
          type: string
          description: The name of the SLO to which the annotation is attached.
        startTime:
          example: '2025-08-07T08:04:05Z'
          type: string
          format: date-time
          description: Start time of the annotation period in RFC3339 format.
        endTime:
          example: '2025-08-07T18:04:05Z'
          type: string
          format: date-time
          description: End time of the annotation period in RFC3339 format.
        status:
          $ref: '#/components/schemas/AnnotationStatus'
        category:
          example: Alert
          type: string
          enum: [Adjustment, Alert, NoDataAnomaly, User]
        labels:
          type: object
          properties:
            key:
              type: array
              items:
                type: string
          example:
            environment:
              - staging
              - production
            customer:
              - basic
              - enterprise
      type: object
    AnnotationPostPayload:
      properties:
        description:
          maxLength: 1000
          type: string
        endTime:
          example: '2025-08-07T18:04:05Z'
          type: string
          format: date-time
          description: End time of the annotation period in RFC3339 format.
        name:
          example: name
          type: string
          description: The name of the annotation.
        project:
          example: default
          type: string
          description: Must conform to DNS (RFC 1123 format).
        slo:
          example: my-slo-name
          type: string
          description: The name of the SLO to which the annotation is attached.
        startTime:
          example: '2025-08-07T08:04:05Z'
          type: string
          format: date-time
          description: Start time of the annotation period in RFC3339 format.
        labels:
          type: object
          properties:
            key:
              type: array
              items:
                type: string
              example: [value1, value2]
      required:
        - description
        - endTime
        - name
        - project
        - slo
        - startTime
      type: object
    AnnotationPutPayload:
      properties:
        description:
          maxLength: 1000
          type: string
        endTime:
          example: '2025-08-07T18:04:05Z'
          type: string
          format: date-time
          description: End time of the annotation period in RFC3339 format.
        project:
          example: default
          type: string
          description: String, must conform to DNS (RFC 1123 format).
        slo:
          example: my-slo-name
          type: string
          description: The name of the SLO to which the annotation is attached.
        startTime:
          example: '2025-08-07T08:04:05Z'
          type: string
          format: date-time
          description: Start time of the annotation period in RFC3339 format.
        labels:
          type: object
          properties:
            key:
              type: array
              items:
                type: string
              example: [value1, value2]
      required:
        - description
        - endTime
        - project
        - slo
        - startTime
      type: object
    AnnotationStatus:
      properties:
        updatedAt:
          example: '2025-08-07T12:04:05Z'
          type: string
          format: date-time
        isSystem:
          example: true
          type: boolean
      type: object
  securitySchemes:
    bearerAuth:
      scheme: bearer
      type: http
      bearerFormat: JWT
