Opal Asgard BFF API

A backend-for-frontend service published in the same public documentation set — 11 paths covering workspace-scoped blocks, smart blocks, smart categories, plans, in-market calendar and experimental plan/block reads, plus two operations that add moments to boards and plans. All operations are categorized Unstable, Proposed or Experimental, so Opal makes no stability guarantee for them. Authenticated with the deprecated `Session-Token` header only.

OpenAPI Specification

opal-asgard-bff-openapi.yml Raw ↑
openapi: 3.0.0
info:
  version: 3.0.0
  title: Asgard BFF API
  license:
    name: Opal API License
    url: https://www.workwithopal.com/api-license
  description: "The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD\
    \ NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted\
    \ as described in [BCP 14](https://tools.ietf.org/html/bcp14) [[RFC2119](https://tools.ietf.org/html/rfc2119)]\
    \ [[RFC8174](https://tools.ietf.org/html/rfc8174)] when, and only when, they appear in all capitals,\
    \ as shown here.\n\n# Design Principles\n\n## Firehose Rule\n\nBy default endpoints include all the\
    \ relevant data that’s accessible to the authenticated user. Clients **MAY** specify filters, ordering,\
    \ pagination, sparse fields, and other limiting mechanisms to pare down the desired data.\n\n*Note:*\
    \ Existing endpoints **MAY NOT** follow this maximalist approach, but new endpoints will, and we **MAY**\
    \ enhance existing endpoints.\n\n## Obscurity\n\nIn order to provide customers with as much privacy\
    \ as possible, many API calls that fail authorization will return `404 Not Found` rather than `403\
    \ Forbidden`. Do not design frontends around the expectation that a `404 Not Found` status code means\
    \ a resource would not be returned given different authentication credentials.\n\n# Authentication\
    \ Strategies\n## OAuth 2.0\nOpal uses OAuth 2.0 (https://oauth.net/2) to authenticate users and grant\
    \ access to protected resources. After registering your application as an OAuth client, you must get\
    \ permission from each user before accessing their account.\n\nThe main steps are:\n\n1. Register\
    \ your application\n2. Direct the user to Opal, to authorize your application\n3. Opal confirm's user\
    \ identity, and asks the user to grant your application permissions\n4. Opal issues tokens your application\
    \ can use to access the user's Opal resources\n5. Your application can begin making requests to the\
    \ Opal API on behalf of the user\n\n### Registering your application\nApplication registration is\
    \ currently a manual process.\n\nTo begin, you will need to provide the following information to the\
    \ Opal integrations team:\n\n- Application name\n- Logo URI\n- Redirect URI\n\nIn return, expect to\
    \ receive:\n\n- Client ID\n  - public\n- Application secret\n  - keep this private\n  - keep this\
    \ written down someplace safe. Opal cannot retrieve this for you if it is lost.\n\n### Authorization\n\
    For a Client to make API requests on behalf of Users, the User must first give consent.\nHere is an\
    \ overview of the consent flow:\n\n1. Direct the User to grant access in Opal\n\n```\nhttps://login.ouropal.com/oauth2/auth?grant_type=authorization_code&scope=offline_access&response_type=code&client_id={client_id}&state={state}&redirect_uri={url_encoded_redirect}\n\
    ```\n\nParameters:\n- `client_id`: Provided by Opal.\n- `grant_type`: Set the value to authorization_code\
    \ to receive a code string that can be exchanged for an access token.\n- `redirect_uri`: Defined by\
    \ Client. After authentication, the user will be directed to this location.\n- `response_type`: The\
    \ value code should be set for refresh tokens to be issued.\n- `scope`: The value offline_access must\
    \ be present if you wish to use refresh tokens.\n- `state`: Defined by the Client. A unique value\
    \ used to validate the response.\n\n\n2. If logged out, User is directed to log in to Opal\n\n3. User\
    \ is redirected to consent page (if the User has not already given consent)\n\n```\nhttps://login.ouropal.com/oauth2/consent?consent_challenge=abc123\n\
    ```\n\n4. If the User grants permission, User is sent to the specified `redirect_uri`\n\n```\nhttps://example.com/defined-by-client?code=Mu9z2DndN7TfXSLaf99O8ReqqXqMabXhSqP5e0jlx_Q.naLKbko-GyfPJRGYcWyclxU0sBGwygPy05OSFww0XZ8&scope=offline_access&state={state}\n\
    ```\n\nParameters:\n- `code`: The Client may use this to get an access token.\n- `scope`: API permissions\
    \ granted to the Client by the User.\n- `state`: The validation string provided by the Client in step\
    \ 1.\n\nIf the User declines the consent prompt, User will be sent to the same `redirect_uri`, but\
    \ with an error parameter :\n\n```\nhttps://example.com/defined-by-client?error=consent+request+denied&state={state}\n\
    ```\n\nParameters:\n- `error`: A brief description of the issue.\n- `state`: The validation string\
    \ provided by the Client in step 1.\n\n### Retrieving Access Token\nYou must make a POST request to\
    \ the token endpoint to get an access token, before the code expires:\n\n```\ncurl -X POST \\\n  https://login.ouropal.com/oauth2/token\
    \ \\\n  -H 'Content-Type: application/x-www-form-urlencoded' \\\n  -d 'code={code}&client_id={client_id}&redirect_uri={url_encoded_redirect}&client_secret={client_secret}&grant_type=authorization_code'\n\
    ```\n\nParameters:\n- `code`\n- `client_id`: Client ID provided by Opal.\n- `client_secret`: Client\
    \ secret provided by Opal.\n- `grant_type`: Set value to authorization_code .\n- `redirect_uri`: Optional.\n\
    \nIf successful, a JSON-formatted response body will contain the access_token and refresh_token:\n\
    \n```json\n{\n  \"access_token\":\"ABC123\",\n  \"token_type\":\"bearer\",\n  \"expires_in\":3600,\n\
    \  \"refresh_token\":\"DEF456\",\n  \"scope\":\"offline_access\"\n}\n```\n\n### Refreshing an Access\
    \ Token\nOnce the access_token expires, you may generate a new one at the same token endpoint, but\
    \ with different parameters.\nNote that in this request, a \"refresh_token\" parameter is used instead\
    \ of \"code\", and the \"grant_type\" value is now \"refresh_token\" instead of \"authorization_code\"\
    .\n\n```\ncurl -X POST \\\n  https://login.ouropal.com/oauth2/token \\\n  -H 'Content-Type: application/x-www-form-urlencoded'\
    \ \\\n  -d 'refresh_token={refresh_token}&client_id={client_id}&redirect_uri={url_encoded_redirect}&client_secret={secret}&grant_type=refresh_token'\n\
    ```\n\nParameters:\n- `client_id`: Client ID provided by Opal.\n- `client_secret`: Client secret provided\
    \ by Opal.\n- `grant_type`: Set value to refresh_token .\n- `redirect_uri`: Optional.\n- `refresh_token`:\
    \ Refresh token value\n\n### Making Authenticated Requests\n\nSet an authorization header in your\
    \ requests, specifying your access token as documented here: https://tools.ietf.org/html/rfc6750#section-2.1.\n\
    \n**NOTE** that the `Authorization` header supercedes the `Session-Token` header described in the\
    \ documentation for many endpoints. Specifying an `Authorization` header means you do not need to\
    \ specify a `Session-Token` header.\n\n```\nAuthorization: Bearer ACCESS_TOKEN\n```\n\nFor example:\n\
    ```\n     GET /resource HTTP/1.1\n     Host: server.example.com\n     Authorization: Bearer mF_9.B5f-4.1JqM\n\
    ```\n\n### Client Revoke/Rolling OAuth secrets\nClient secrets must be kept secret and not exposed\
    \ outside of the token retrieval requests. If a secret has been potentially compromised, please notify\
    \ Opal as soon as possible and let us know the OAuth client id associated with the secret. We will\
    \ roll/update the secret, which will invalidate all existing access and refresh tokens. Invalidating\
    \ tokens will cause users to need to reauthenticate, but consent should be remembered.\n"
servers:
- url: https://login.ouropal.com
x-tagGroups:
- name: ⚠️  Unstable
  tags:
  - Plans
  - Blocks
  - Custom Fields
- name: ℹ️ Proposed
  tags:
  - Moments
  - Smart Blocks
  - In Market
- name: 🔮 Experimental
  tags:
  - Experimental
components:
  securitySchemes:
    api_key:
      type: apiKey
      description: (Deprecated) This API also supports authentication via an API or session token set
        in the request headers.
      in: header
      name: Session-Token
  schemas:
    blocks_by_category:
      type: object
      required:
      - by_id
      - by_category_with_position
      additionalProperties: false
      properties:
        by_category_with_position:
          type: object
          description: 'An object where the keys represent a Category `id` and the value is a list of
            objects describing the positions of block within the category.

            '
          additionalProperties:
            type: array
            items:
              type: object
              additionalProperties: false
              required:
              - duration
              - end_at
              - id
              - row_index
              - start_at
              properties:
                duration:
                  type: string
                  nullable: true
                  description: 'ISO 8601 duration in days (P{n}D). Week and month durations are normalized
                    to days when start_at is set.

                    '
                end_at:
                  type: string
                  format: ISO8601
                  nullable: true
                  deprecated: true
                  description: 'DEPRECATED: migrate to `duration`.'
                id:
                  type: string
                  format: uuid
                row_index:
                  type: integer
                  description: 'Signifies the vertical row offset within a swimlane.

                    '
                start_at:
                  type: string
                  format: ISO8601
                  nullable: true
                  description: The starting date of the block as an ISO8601 date with no timestamp.
        by_id:
          type: object
          description: 'An object where the keys represent a Block `id` and the value is a full Block
            object. Used for fast access to a block by its `id` when used in conjunction with the `by_category_with_position`
            structure.

            '
          additionalProperties:
            type: object
            required:
            - category_id
            - category_type
            - child_plan_id
            - color
            - connectors
            - created_at
            - description
            - duration
            - end_date
            - id
            - image_id
            - is_template
            - is_workspace_wide_template
            - owner_id
            - paired_moment_board_object_ids
            - paired_moment_id
            - row_index
            - start_at
            - template_description
            - template_name
            - title
            - y_scale
            additionalProperties: false
            properties:
              category_id:
                type: string
                format: uuid
                nullable: true
              category_type:
                nullable: true
                allOf:
                - type: object
                  nullable: true
                  required:
                  - id
                  - name
                  - description
                  - deactivated_at
                  additionalProperties: false
                  properties:
                    id:
                      type: string
                      format: uuid
                    name:
                      type: string
                      nullable: false
                      description: The name that will be displayed in the Opal application UI.
                    description:
                      type: string
                      nullable: true
                      description: A description of the record.
                    deactivated_at:
                      type: string
                      format: date-time
                      nullable: true
                      description: The timestamp when the category type was deactivated, if it has been
                        deactivated.
                    supported_paired_type:
                      type: string
                      nullable: true
                      default: null
                      enum:
                      - moment
                      - null
                      description: Whether blocks of this type will have resources of the given type paired
                        with them. Moment pairing allows teams to work with the same resources from the
                        Plan (via blocks) or from a Board or Calendar (via Moments). Once set to 'moment',
                        this property cannot be set back to null. Blocks created with a type that supports
                        moment pairing will always have paired moments. Conversely, blocks created with
                        types that do not support moment pairing will not have paired moments (unless
                        moment pairing support is added to the type later).
              child_plan_id:
                type: string
                nullable: true
              color:
                type: string
                nullable: true
              connectors:
                type: array
                nullable: false
                items:
                  type: object
                  required:
                  - id
                  - view_id
                  - category_id
                  additionalProperties: false
                  properties:
                    id:
                      type: string
                      format: uuid
                    view_id:
                      type: string
                      format: uuid
                    category_id:
                      type: string
                      format: uuid
                      nullable: true
              created_at:
                type: string
                format: ISO8601
              description:
                type: string
                nullable: true
              duration:
                type: string
                nullable: true
                description: ISO 8601 duration string (e.g. P10D, P5W, P3M). Clients compute end date
                  as start_date + duration.
              end_date:
                type: string
                format: ISO8601
                nullable: true
                deprecated: true
                description: 'DEPRECATED: migrate to `duration`.'
              id:
                type: string
                format: uuid
              image_id:
                type: string
                format: uuid
                nullable: true
              is_template:
                type: boolean
              is_workspace_wide_template:
                type: boolean
              owner_id:
                type: string
                format: uuid
              paired_moment_board_object_ids:
                type: array
                items:
                  type: string
                  format: uuid
              paired_moment_id:
                type: string
                format: uuid
                nullable: true
                description: The UUID of the paired moment, if one exists for this block.
              row_index:
                type: integer
              start_at:
                type: string
                format: ISO8601
                nullable: true
              template_description:
                type: string
                nullable: true
              template_name:
                type: string
                nullable: true
              title:
                type: string
              y_scale:
                type: integer
    block_connector:
      type: object
      required:
      - id
      - category
      - parent_block
      - view
      properties:
        id:
          type: string
          format: uuid
        category:
          nullable: true
          allOf:
          - type: object
            required:
            - id
            - name
            additionalProperties: false
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
                nullable: true
        parent_block:
          type: object
          required:
          - id
          - name
          additionalProperties: false
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
              nullable: true
        view:
          type: object
          required:
          - id
          - name
          additionalProperties: false
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
              nullable: true
    category_hierarchy:
      type: object
      required:
      - by_id
      - hierarchy
      additionalProperties: false
      properties:
        by_id:
          type: object
          description: 'An object where the keys represent a Category `id` and the value is a timeline_category
            object. Used for fast access to a category by its `id` when used in conjunction with the `hierarchy`
            structure.

            '
          additionalProperties:
            type: object
            required:
            - chart_id
            - id
            - image_url
            - kind
            - position
            - settings
            - title
            additionalProperties: false
            properties:
              chart_id:
                type: string
                format: uuid
                nullable: true
              id:
                type: string
                format: uuid
              image_url:
                type: string
                nullable: true
              kind:
                type: string
                description: 'Indicates the variant of category this is. In the case of a smart collection,
                  this the top level container

                  is always "smart_swimlane" while its child categories are always "derived_swimlane"

                  '
                enum:
                - derived_swimlane
                - graph_swimlane
                - group
                - smart_swimlane
                - swimlane
              position:
                type: integer
              settings:
                nullable: true
                oneOf:
                - type: object
                  additionalProperties: false
                  required:
                  - row_size
                  - template_id
                  - type
                  - view_mode
                  properties:
                    type:
                      nullable: true
                      allOf:
                      - type: object
                        nullable: true
                        required:
                        - id
                        - name
                        - description
                        - deactivated_at
                        additionalProperties: false
                        properties:
                          id:
                            type: string
                            format: uuid
                          name:
                            type: string
                            nullable: false
                            description: The name that will be displayed in the Opal application UI.
                          description:
                            type: string
                            nullable: true
                            description: A description of the record.
                          deactivated_at:
                            type: string
                            format: date-time
                            nullable: true
                            description: The timestamp when the category type was deactivated, if it has
                              been deactivated.
                          supported_paired_type:
                            type: string
                            nullable: true
                            default: null
                            enum:
                            - moment
                            - null
                            description: Whether blocks of this type will have resources of the given
                              type paired with them. Moment pairing allows teams to work with the same
                              resources from the Plan (via blocks) or from a Board or Calendar (via Moments).
                              Once set to 'moment', this property cannot be set back to null. Blocks created
                              with a type that supports moment pairing will always have paired moments.
                              Conversely, blocks created with types that do not support moment pairing
                              will not have paired moments (unless moment pairing support is added to
                              the type later).
                    row_size:
                      type: string
                      enum:
                      - small
                      - medium
                      - large
                    template_id:
                      type: string
                      format: uuid
                      nullable: true
                    view_mode:
                      type: string
                      enum:
                      - default
                      - condensed
                - type: object
                  additionalProperties: false
                  required:
                  - resource_type
                  properties:
                    resource_type:
                      type: string
                      enum:
                      - user
                      - user_group
              title:
                type: string
                nullable: true
        hierarchy:
          type: array
          items:
            type: object
            required:
            - id
            - children
            additionalProperties: false
            properties:
              id:
                type: string
                format: uuid
                description: The ID of a category.
              children:
                type: array
                items:
                  type: object
                  required:
                  - id
                  - children
                  additionalProperties: false
                  properties:
                    id:
                      type: string
                      format: uuid
                      description: The ID of a category.
                    children:
                      type: array
                      maxItems: 0
    category_type:
      type: object
      required:
      - deactivated_at
      - description
      - id
      - name
      - supported_paired_type
      additionalProperties: false
      properties:
        deactivated_at:
          type: string
          format: ISO8601
          nullable: true
        description:
          type: string
          nullable: true
        id:
          type: string
          format: uuid
        name:
          type: string
        supported_paired_type:
          type: string
          nullable: true
          default: null
          enum:
          - moment
          - null
          description: Whether blocks of this type will have resources of the given type paired with them.
            Moment pairing allows teams to work with the same resources from the Plan (via blocks) or
            from a Board or Calendar (via Moments). Once set to 'moment', this property cannot be set
            back to null. Blocks created with a type that supports moment pairing will always have paired
            moments. Conversely, blocks created with types that do not support moment pairing will not
            have paired moments (unless moment pairing support is added to the type later).
    chart:
      type: object
      required:
      - data
      - id
      - title
      additionalProperties: false
      properties:
        data:
          type: object
          required:
          - seriesData
          - seriesKeys
          nullable: true
          additionalProperties: false
          properties:
            seriesData:
              type: array
              items:
                type: object
                required:
                - epochDate
                properties:
                  epochDate:
                    type: integer
                    nullable: false
            seriesKeys:
              type: array
              items:
                type: string
        id:
          type: string
          format: uuid
        title:
          type: string
          nullable: true
    color:
      type: object
      required:
      - color
      - id
      - label
      additionalProperties: false
      properties:
        color:
          type: string
        id:
          type: string
          format: uuid
        label:
          type: string
          nullable: true
    connector_candidate:
      type: object
      required:
      - block
      - supportive_category_id
      - supportive_view_id
      - child_candidates
      - category_type
      - start_date
      - end_date
      additionalProperties: false
      properties:
        block:
          type: object
          required:
          - id
          - name
          additionalProperties: false
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
              nullable: true
        category_type:
          nullable: true
          type: object
          required:
          - id
          - name
          additionalProperties: false
          properties:
            id:
              type: string
              format: uuid
            name:
              type: string
              nullable: true
        supportive_category_id:
          type: string
          format: uuid
          nullable: true
        supportive_view_id:
          type: string
          format: uuid
          nullable: true
        start_date:
          type: string
          format: date
        end_date:
          type: string
          format: date
        child_candidates:
          type: array
          nullable: true
          items:
            type: object
            required:
            - block
            - supportive_category_id
            - supportive_view_id
            - child_candidates
            additionalProperties: false
            properties:
              block:
                type: object
                required:
                - id
                - name
                additionalProperties: false
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
                    nullable: true
              supportive_category_id:
                type: string
                format: uuid
                nullable: true
              supportive_view_id:
                type: string
                format: uuid
                nullable: true
              child_candidates:
                type: string
                nullable: true
    key_date:
      type: object
      required:
      - color
      - end_date
      - id
      - start_date
      - title
      additionalProperties: false
      properties:
        color:
          type: string
          nullable: true
        end_date:
          type: string
          format: ISO8601
          nullable: true
        id:
          type: string
          format: uuid
        start_date:
          type: string
          format: ISO8601
        title:
          type: string
    resource_reference:
      type: object
      required:
      - id
      - name
      additionalProperties: false
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          nullable: true
    swimlane_position:
      type: object
      additionalProperties: false
      required:
      - duration
      - end_at
      - id
      - row_index
      - start_at
      properties:
        duration:
          type: string
          nullable: true
          description: 'ISO 8601 duration in days (P{n}D). Week and month durations are normalized to
            days when start_at is set.

            '
        end_at:
          type: string
          format: ISO8601
          nullable: true
          deprecated: true
          description: 'DEPRECATED: migrate to `duration`.'
        id:
          type: string
          format: uuid
        row_index:
          type: integer
          description: 'Signifies the vertical row offset within a swimlane.

            '
        start_at:
          type: string
          format: ISO8601
          nullable: true
          description: The starting date of the block as an ISO8601 date with no timestamp.
    timeline_block:
      type: object
      required:
      - category_id
      - category_type
      - child_plan_id
      - color
      - connectors
      - created_at
      - description
      - duration
      - end_date
      - id
      - image_id
      - is_template
      - is_workspace_wide_template
      - owner_id
      - paired_moment_board_object_ids
      - paired_moment_id
      - row_index
      - start_at
      - template_description
      - template_name
      - title
      - y_scale
      additionalProperties: false
      properties:
        category_id:
          type: string
          format: uuid
          nullable: true
        category_type:
          nullable: true
          allOf:
          - type: object
            nullable: true
            required:
            - id
            - name
            - description
            - deactivated_at
            additionalProperties: false
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
                nullable: false
                description: The name that will be displayed in the Opal application UI.
              description:
                type: string
                nullable: true
                description: A description of the record.
              deactivated_at:
                type: string
                format: date-time
                nullable: true
                description: The timestamp when the category type was deactivated, if it has been deactivated.
              supported_paired_type:
                type: string
                nullable: true
                default: null
                enum:
                - moment
                - null
                description: Whether blocks of this type will have resources of the given type paired
                  with them. Moment pairing allows teams to work with the same resources from the Plan
                  (via blocks) or from a Board or Calendar (via Moments). Once set to 'moment', this property
                  cannot be set back to null. Blocks created with a type that supports moment pairing
                  will always have paired moments. Conversely, blocks created with types that do not support
                  moment pairing will not have paired moments (unless moment pairing support is added
                  to the type later).
        child_plan_id:
          type: string
          nullable: true
        color:
          type: string
          nullable: true
        connectors:
          type: array
          nullable: false
          items:
            type: object
            required:
            - id
            - view_id
            - category_id
            additionalProperties: false
            properties:
              id:
                type: string
                format: uuid
              view_id:
                type: string
                format: uuid
              category_id:
                type: string
                format: uuid
                nullable: true
        created_at:
          type: string
          format: ISO8601
        description:
          type: string
          nullable: true
        duration:
          type: string
          nullable: true
          description: ISO 8601 duration string (e.g. P10D, P5W, P3M). Clients compute end date as start_date
            + duration.
        end_date:
          type: string
          format: ISO8601
          nullable: true
          deprecated: true
          description: 'DEPRECATED: migrate to `duration`.'
     

# --- truncated at 32 KB (475 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/opal/refs/heads/main/openapi/opal-asgard-bff-openapi.yml