openapi: 3.0.1
info:
  title: Asset Service API Specification
  description: "This page describes how to integrate with the **Asset Service** on
    a technical level.\n[**The Foundation API Guide**](../../../docs/api-guides/platform/foundation)
    provides a higher-level overview of assets.\n\n-----\n\n## REST Resources\n\n
    The Asset Service provides resources for managing and retrieving **assets** and
    their **representations**.\n\n### Asset\n\nAssets are templated content that can
    be dynamically resolved with specific input data. They enable the Banqup platform\n
    to deliver personalized and localized content, such as notifications, HTML pages,
    or plain text, by filling in\nplaceholders within the templates.\n\nAn example
    of a **JSON asset** that uses JSONata expressions for dynamic content:\n\n```json\n\
    {\n  \"notification\": {\n    \"title\": \"data.matchInfo.homeTeam & ' vs. ' &
    data.matchInfo.awayTeam\",\n    \"body\": \"data.matchInfo.status\"\n  },\n  \"\
    data\": {\n    \"Nick\": \"data.user.nickname\",\n    \"Room\": \"data.matchInfo.homeTeam
    & 'VS' & data.matchInfo.awayTeam\"\n  },\n  \"option\": {\n    \"ttl\": \"data.defaults.ttl\"\
    ,\n    \"collapse\": \"$collapseKey\",\n    \"priority\": \"$priorityOverride
    ? $priorityOverride : data.defaults.priority\"\n  }\n}\n```\n\nThis asset can
    then be **resolved** by providing input data, resulting in personalized content:\n\
    \n```json\n{\n  \"notification\": {\n    \"title\": \"Portugal vs. Denmark\",\n\
    \    \"body\": \"great match!\"\n  },\n  \"data\": {\n    \"Nick\": \"Mario\"\
    ,\n    \"Room\": \"PortugalVSDenmark\"\n  },\n  \"option\": {\n    \"ttl\": 4800,\n\
    \    \"priority\": \"NORMAL\"\n  }\n}\n```\n\nThe Asset Service supports various
    asset types, including JSON, HTML, and plain text, each capable of using different\n
    templating languages like JSONata and Freemarker for dynamic content.\n\n### Representation\n
    \nRepresentations are the actual content files stored within the Asset Service.
    These can be any type of file, such as\ntext documents, images, or templated content
    (like the assets described above). The Asset Service allows for the\nstorage,
    retrieval, updating, and deletion of these representations.\n\nRepresentations
    are accessed via their full path, which can include directories, allowing for
    a hierarchical\norganization of content.\n\n**Example: Retrieving a representation**\n
    \nIf you have a representation stored at `subdir/invoice.en-US.txt`, retrieving
    it would return its raw content.\n\n-----\n\n## Working with Assets\n\n### Retrieving
    Assets\n\nTo retrieve an asset, you'll perform a **GET** request to the \n[**/core/asset/v1/assets/:asset**](../../../docs/foundation/asset/retrieve-asset)
    endpoint. You can specify fallback\ncontent types and languages through `Accept`
    and `Accept-Language` headers, respectively, to ensure content negotiation\ndelivers
    the most suitable representation.\n\nFor example, to retrieve an asset named `asset/iam/onboarding/template.en-US.pushnotification.json`:\n
    \n```http\nGET /v1/assets/asset/iam/onboarding/template\nAccept: application/btx-pushnotification+json,
    application/json\nAccept-Language: en-GB, en\n```\n\nA successful response (HTTP
    200) will return the raw, templated content of the asset.\n\n### Resolving Assets\n
    \nTo resolve an asset (i.e., fill its placeholders with data), you'll perform
    a **POST** request to the\n[**/core/asset/v1/assets/:asset**](../../../docs/foundation/asset/resolve-asset)
    endpoint,\nproviding the input data in the request body. This allows the Asset
    Service to process\nthe asset's template and return the fully rendered content.\n
    \nFor example, to resolve the same asset with specific user and match information:\n
    \n```http\nPOST /v1/assets/asset/iam/onboarding/template.en-US.pushnotification.json\n
    Content-Type: application/json\n\n{\n  \"user\": {\n    \"nickname\": \"Mario\"\
    \n  },\n  \"matchInfo\": {\n    \"homeTeam\": \"Portugal\",\n    \"awayTeam\"
    : \"Denmark\",\n    \"status\": \"great match!\"\n  },\n  \"defaults\": {\n  \
    \  \"ttl\": 4800,\n    \"priority\": \"NORMAL\"\n  }\n}\n```\n\nA successful response
    (HTTP 200) will return the asset with all its placeholders resolved by the provided
    input data.\n\n-----\n\n## Managing Representations\n\n### Retrieving Representations\n
    \nYou can retrieve the content of a specific representation or list the contents
    of a directory using **GET** requests to\nthe [**/core/asset/v1/representations/:path**](../../../docs/foundation/asset/retrieve-representation)
    endpoint.\n\n- To retrieve the content of a file, provide its full path.\n- To
    list directory contents, append a trailing slash to the directory path (e.g.,
    `/v1/representations/subdir/`).\n\nA successful retrieve will return an HTTP 200
    Ok response.\n\n### Uploading or Updating Representations\n\nTo upload new content
    or update an existing representation, perform a **PUT** request to\n[**/core/asset/v1/representations/:path**](../../../docs/foundation/asset/upload-representation),\n
    providing the content in the request body with `Content-Type: application/octet-stream`.\n
    \nA successful upload will return an HTTP 201 Created response.\nA successful
    update will return an HTTP 200 Ok response.\n\n### Deleting Representations\n\n
    To delete a representation or an entire directory, perform a **DELETE** request
    to\n[**/core/asset/v1/representations/:path**](../../../docs/foundation/asset/delete-representation).\n
    \n- To delete a representation, provide its full path.\n- To delete a directory,
    append a trailing slash to the directory path (e.g., `/v1/representations/subdir/`).\n
    \nA successful deletion will return an HTTP 204 No Content response.\n\n-----\n
    \n## Security\n\nAccess to asset retrieval, resolution, and representation management
    is controlled by specific security scopes. For\ninstance, `asset_retrieve` is
    required to retrieve an asset, `asset_resolve` for resolving an asset, and\n`representation_read`
    and `representation_write` for managing representations. Permissions are typically
    granted through\nan OAuth security scheme.\n"
  version: 2.1.11
servers:
- description: Generated server url
  url: https://api.cve.btx.eu.banqup.com/core/asset
paths:
  /v1/assets/{asset}:
    get:
      tags:
      - Asset
      summary: Retrieve asset
      description: Retrieve asset
      operationId: retrieveAsset
      parameters:
      - name: Accept
        in: header
        description: Fallback content types for content negotiation
        required: false
        schema:
          type: array
          items:
            type: string
        example:
        - application/btx-pushnotification+json
        - application/json
      - name: Accept-Language
        in: header
        description: Fallback languages for language negotiation
        required: false
        schema:
          type: array
          items:
            type: string
        example:
        - en-GB
        - en
      - name: asset
        in: path
        description: Asset to retrieve
        required: true
        schema:
          type: string
        example: asset/iam/onboarding/template.en-US.pushnotification.json
      - name: type
        in: query
        description: Content type of the asset
        required: false
        schema:
          type: string
        example: application/btx-pushnotification+json
      - name: l
        in: query
        description: Language of the asset
        required: false
        schema:
          type: string
        example: en-GB
      responses:
        '200':
          description: Retrieved asset
          content:
            application/json:
              schema:
                type: string
              examples:
                json-asset-with-jsonata:
                  summary: JSON with JSONata placeholders
                  description: An example of a JSON asset that uses JSONata expressions
                    for dynamic content.
                  value:
                    notification:
                      title: data.matchInfo.homeTeam & ' vs. ' & data.matchInfo.awayTeam
                      body: data.matchInfo.status
                    data:
                      Nick: data.user.nickname
                      Room: data.matchInfo.homeTeam & 'VS' & data.matchInfo.awayTeam
                    option:
                      ttl: data.defaults.ttl
                      collapse: $collapseKey
                      priority: '$priorityOverride ? $priorityOverride : data.defaults.priority'
            text/html:
              schema:
                type: string
              examples:
                html-asset-with-freemarker:
                  summary: HTML with Freemarker placeholders
                  description: An example of an HTML asset that uses Freemarker templates
                    for dynamic content.
                  value: |
                    <!DOCTYPE html>
                    <html>
                    <head>
                      <title>${matchInfo.homeTeam} vs. ${matchInfo.awayTeam}</title>
                    </head>
                    <body>
                      <h1>Match Status: ${matchInfo.status}</h1>
                      <p>Hello, ${user.nickname}!</p>
                      <p>Welcome to the room for ${matchInfo.homeTeam}VS${matchInfo.awayTeam}.</p>
                    </body>
                    </html>
            text/plain:
              schema:
                type: string
              examples:
                text-asset-with-freemarker:
                  summary: Plain text with Freemarker placeholders
                  description: An example of a plain text asset that uses Freemarker
                    templates for dynamic content.
                  value: |
                    Match: ${matchInfo.homeTeam} vs. ${matchInfo.awayTeam}
                    Status: ${matchInfo.status}
                    User: ${user.nickname}
        '401':
          description: Unauthorized Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 401
                error: UNAUTHENTICATED
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Unauthorized
                detail: Access to the requested resource lacks valid authentication
                  credentials.
        '403':
          description: Forbidden Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 403
                error: PERMISSION_DENIED
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Forbidden
                detail: Access to the requested resource was denied.
        '404':
          description: Not Found Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 404
                error: NOT_FOUND
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Not Found
                detail: The HTTP method was not allowed on this endpoint.
        '406':
          description: Not Acceptable Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
        '500':
          description: Internal Server Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 500
                error: INTERNAL
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Internal Server Error
                detail: The server encountered an unexpected error.
      security:
      - oauth2:
        - asset_retrieve
    post:
      tags:
      - Asset
      summary: Resolve asset
      description: Resolve asset
      operationId: resolveAsset
      parameters:
      - name: Accept
        in: header
        description: Fallback content types for content negotiation
        required: false
        schema:
          type: array
          items:
            type: string
        example:
        - application/btx-pushnotification+json
        - application/json
      - name: Accept-Language
        in: header
        description: Fallback languages for language negotiation
        required: false
        schema:
          type: array
          items:
            type: string
        example:
        - en-GB
        - en
      - name: asset
        in: path
        description: Asset to resolve
        required: true
        schema:
          type: string
        example: asset/iam/onboarding/template.en-US.pushnotification.json
      - name: type
        in: query
        description: Content type of the asset
        required: false
        schema:
          type: string
        example: application/btx-pushnotification+json
      - name: l
        in: query
        description: Language of the asset
        required: false
        schema:
          type: string
        example: en-GB
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AssetInput'
        required: true
      responses:
        '200':
          description: Resolved asset
          content:
            application/json:
              schema:
                type: string
              examples:
                resolved-json-asset:
                  summary: Resolved JSON asset
                  description: An example of a JSON asset after its placeholders have
                    been resolved.
                  value:
                    notification:
                      title: Portugal vs. Denmark
                      body: great match!
                    data:
                      Nick: Mario
                      Room: PortugalVSDenmark
                    option:
                      ttl: 4800
                      priority: NORMAL
            text/html:
              schema:
                type: string
              examples:
                resolved-html-asset:
                  summary: Resolved HTML asset
                  description: An example of an HTML asset after its placeholders
                    have been resolved.
                  value: |
                    <!DOCTYPE html>
                    <html>
                    <head>
                      <title>Portugal vs. Denmark</title>
                    </head>
                    <body>
                      <h1>Match Status: great match!</h1>
                      <p>Hello, Mario!</p>
                      <p>Welcome to the room for PortugalVSDenmark.</p>
                    </body>
                    </html>
            text/plain:
              schema:
                type: string
              examples:
                resolved-text-asset:
                  summary: Resolved plain text asset
                  description: An example of a plain text asset after its placeholders
                    have been resolved.
                  value: |
                    Match: Portugal vs. Denmark
                    Status: great match!
                    User: Mario
        '400':
          description: Invalid Request
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 400
                error: BAD_REQUEST
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Bad Request
                detail: Bad Request message details.
        '401':
          description: Unauthorized Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 401
                error: UNAUTHENTICATED
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Unauthorized
                detail: Access to the requested resource lacks valid authentication
                  credentials.
        '403':
          description: Forbidden Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 403
                error: PERMISSION_DENIED
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Forbidden
                detail: Access to the requested resource was denied.
        '404':
          description: Not Found Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 404
                error: NOT_FOUND
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Not Found
                detail: The HTTP method was not allowed on this endpoint.
        '406':
          description: Not Acceptable Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
        '500':
          description: Internal Server Error
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ApiErrorProblemDetail'
              example:
                status: 500
                error: INTERNAL
                requestId: a78150d2-7913-4ea6-933f-286cadac6745
                timestamp: 2018-08-27T12:34:50Z
                type: about:blank
                title: Internal Server Error
                detail: The server encountered an unexpected error.
      security:
      - oauth2:
        - asset_resolve
components:
  schemas:
    ApiErrorProblemDetail:
      required:
      - error
      - requestId
      - timestamp
      type: object
      properties:
        status:
          type: integer
          format: int32
        error:
          type: string
        requestId:
          type: string
        timestamp:
          type: string
          format: date-time
        type:
          type: string
          format: uri
        title:
          type: string
        detail:
          type: string
        instance:
          type: string
          format: uri
        problems:
          type: array
          items:
            $ref: '#/components/schemas/NestedProblem'
        properties:
          type: object
          additionalProperties:
            type: object
    NestedProblem:
      required:
      - detail
      - error
      - title
      type: object
      properties:
        error:
          type: string
        title:
          type: string
        detail:
          type: string
        type:
          type: string
          format: uri
    UploadRepresentationRequest:
      required:
      - path
      type: object
      properties:
        path:
          minLength: 1
          type: string
          description: The representation's path.
          example: dynamic/logos/5aca77d6-995d-4be8-92fe-e27a85113e5c/logo_invoice.png
        fileSize:
          type: integer
          description: The representation's size.
          format: int64
          example: 153642
      description: The path, type and size of the representation to create or update.
      example:
        path: dynamic/logos/5aca77d6-995d-4be8-92fe-e27a85113e5c/logo_invoice.png
        fileSize: 153642
    UploadRepresentationResponse:
      type: object
      properties:
        uploadUrl:
          type: string
          description: The representation's upload url.
          format: url
          example: 
            https://storage.googleapis.com/example-bucket/cat.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com%2F20181026%2Fus-central1%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T181309Z&X-Goog-Expires=900&X-Goog-SignedHeaders=host&X-Goog-Signature=247a2aa45f169edf4d187d54e7cc46e4731b1e6273242c4f4c39a1d2507a0e58706e25e3a85a7dbb891d62afa8496def8e260c1db863d9ace85ff0a184b894b117fe46d1225c82f2aa19efd52cf21d3e2022b3b868dcc1aca2741951ed5bf3bb25a34f5e9316a2841e8ff4c530b22ceaa1c5ce09c7cbb5732631510c20580e61723f5594de3aea497f195456a2ff2bdd0d13bad47289d8611b6f9cfeef0c46c91a455b94e90a66924f722292d21e24d31dcfb38ce0c0f353ffa5a9756fc2a9f2b40bc2113206a81e324fc4fd6823a29163fa845c8ae7eca1fcf6e5bb48b3200983c56c5ca81fffb151cca7402beddfc4a76b133447032ea7abedc098d2eb14a7
      description: An upload url for uploading or updating representation.
      example:
        uploadUrl: 
          https://storage.googleapis.com/example-bucket/cat.jpeg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=example%40example-project.iam.gserviceaccount.com%2F20181026%2Fus-central1%2Fstorage%2Fgoog4_request&X-Goog-Date=20181026T181309Z&X-Goog-Expires=900&X-Goog-SignedHeaders=host&X-Goog-Signature=247a2aa45f169edf4d187d54e7cc46e4731b1e6273242c4f4c39a1d2507a0e58706e25e3a85a7dbb891d62afa8496def8e260c1db863d9ace85ff0a184b894b117fe46d1225c82f2aa19efd52cf21d3e2022b3b868dcc1aca2741951ed5bf3bb25a34f5e9316a2841e8ff4c530b22ceaa1c5ce09c7cbb5732631510c20580e61723f5594de3aea497f195456a2ff2bdd0d13bad47289d8611b6f9cfeef0c46c91a455b94e90a66924f722292d21e24d31dcfb38ce0c0f353ffa5a9756fc2a9f2b40bc2113206a81e324fc4fd6823a29163fa845c8ae7eca1fcf6e5bb48b3200983c56c5ca81fffb151cca7402beddfc4a76b133447032ea7abedc098d2eb14a7
    AssetInput:
      type: object
      properties:
        recipient:
          $ref: '#/components/schemas/Recipient'
        data:
          type: object
          description: A flexible object to hold data specific to the asset being
            requested.
          example:
            matchInfo:
              homeTeam: Portugal
              awayTeam: Denmark
              status: great match!
            user:
              nickname: Mario
            defaults:
              ttl: 4800
              priority: NORMAL
      description: Input data for the asset
      example:
        recipient:
          id: 8c66dc06-424d-480e-a827-fb72101d9ea6
          firstName: Peter
          lastName: Smith
          language: en-GB
          email: peter.smith@example.com
          mobile: '+447123456789'
          brand: BTX
        data:
          matchInfo:
            homeTeam: Portugal
            awayTeam: Denmark
            status: great match!
          user:
            nickname: Mario
          defaults:
            ttl: 4800
            priority: NORMAL
    Recipient:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier for the recipient.
          example: 8c66dc06-424d-480e-a827-fb72101d9ea6
        firstName:
          type: string
          description: The recipient's first name.
          example: Peter
        lastName:
          type: string
          description: The recipient's last name.
          example: Smith
        language:
          type: string
          description: The preferred language of the recipient.
          example: en-GB
        email:
          type: string
          description: The recipient's email address.
          example: peter.smith@example.com
        mobile:
          type: string
          description: The recipient's mobile number.
          example: '+447123456789'
        brand:
          type: string
          description: The brand associated with the recipient.
          example: Banqup
      description: Represents the recipient of the asset.
      example:
        id: 8c66dc06-424d-480e-a827-fb72101d9ea6
        firstName: Peter
        lastName: Smith
        language: en-GB
        email: peter.smith@example.com
        mobile: '+447123456789'
        brand: BTX
    DirectoryListing:
      type: object
      properties:
        representations:
          type: array
          description: The representation's path.
          example: subdir/invoice.en-US.txt
          items:
            type: string
            description: The representation's path.
            example: subdir/invoice.en-US.txt
      description: A list of representations and subdirectories within this directory.
      example:
        representations:
        - invoice.en-US.html
        - invoice.nl-NL.html
        - invoice.nl-BE.html
        - subdir
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: https://api.cve.btx.eu.banqup.com/oauth2/client_credential/gettoken
          scopes:
            info: Scopes are endpoint-specific, see each endpoint for required scope.
        authorizationCode:
          authorizationUrl: https://api.cve.btx.eu.banqup.com/oauth2/auth
          tokenUrl: https://api.cve.btx.eu.banqup.com/oauth2/token
          scopes:
            info: Scopes are endpoint-specific, see each endpoint for required scope.
