openapi: 3.0.1
info:
  title: Service Engine APIs for HTM voucher suppliers
  description: Service Engine APIs for HTM voucher suppliers, this means all instances responsible for supplying vouchers. These are NOT the CRUD APIs to the data hub. These are ALSO NOT the api's for sales touchpoints.
  version: "1.0"
servers:
  - url: https://services.acc.api.htm.nl/abt/abtvouchers/1.0
paths:
  /voucherdefinitions:
    get:
      tags:
        - Vouchers
      summary: Get a list of all voucher definitions that a touchpoint is allowed to issue
      description: |-
        Get a list of all voucher definitions that the calling touchpoint is allowed to issue.\
        Essentially, this means that only voucher definitions that have active sellingPeriods for touchpoints within the same 
        retailer as the calling touchpoint are returned.
        Voucher definitions are modeled using the same model as HTM products. This means that voucher definitions look like "products" (have a productId, mostly the same attributes as HTM products, etc.) but most attributes need to be interpreted differently.\
        For vouchers:
        - productCategory should always be "voucher"
        - requiredProduct contains the productId of the product that is acquired when redeeming the voucher
        - sellingPeriods denote which touchpoints are allowed to issue vouchers from a given definition and what their issuance limits are
        - MandatoryCustomerDataItems denote the "voucher claims" which are checked against known values that should match the customer input, to be allowed to redeem the voucher
        
        When a requiredProduct is configured, all attributes of the requiredProduct are also prerequisites for redeeming the voucher; thus they do not need to also be configured for the voucher definition. The requiredProduct itself is the single source of truth for this; and voucher definitions do not need to be updated if the requirements of the requiredProduct change. For example, if the requiredProduct requires an OVpay token, an OVpay token is automatically required to redeem issued vouchers.
      parameters:
        - name: touchpointId
          in: query
          required: false
          description: |
            Filter the voucher definitions on a specific touchpointId. This means that only voucher definitions with active selling periods for the specified touchpoint are returned.
            This query parameter is only intended for administrative purposes, since the touchpoint associated with the access token used in the request is used to determine which voucher definitions are returned. This query parameter can be used to retrieve voucher definitions for other touchpoints within the same retailer, for example to retrieve voucher definitions for a specific sales touchpoint that is different from the calling touchpoint.
          schema:
            type: integer
            example: 12
        - name: productId
          in: query
          required: false
          description: Return a specific voucher definition by its productId.
          schema:
            type: integer
            example: 321
        - name: requiredProductId
          in: query
          required: false
          description: Filter the voucher definitions on a specific requiredProductId (denoting the product that is acquired when redeeming the voucher). This means that only voucher definitions that have the specified productId in their requiredProducts array are returned.
          schema:
            type: integer
            example: 126
        - name: showOnlyActive
          in: query
          required: false
          description: Filter the voucher definitions on active selling periods. If true, only voucher definitions with at least one active selling period are returned. If false, all voucher definitions are returned regardless of their selling periods.
          schema:
            type: boolean
            example: true
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/supplierTouchpointVoucherDefinitionsListResponse"
              examples:
                No products / Empty list:
                  summary: No products / Empty list
                  description: No products
                  value: { "voucherDefinitions": [] }
                List containing one voucher definition (called by touchpointId 12):
                  summary: List containing one voucher definition (called by touchpointId 12)
                  description: |- 
                   List containing one voucher definition for a voucher that can be redeemed for the product "Ooievaarspas voor AOW-ers in Den Haag".\
                   In this case, the voucher definition has a sellingPrice of 0, which means that vouchers issued from this voucher definition can be redeemed to acquire the requiredProduct for free. The requiredProduct also has a sellingPrice of 0, so no "discount" is shown to the customer; just the voucher's amountInclTax.\
                   To issue vouchers for this voucher definition, the calling touchpoint must also provide voucherClaims (values to be checked against customer input when redeeming the voucher) for each of the mandatoryCustomerDataItems of the voucher definition (in this case, a PAD birthdate).\
                   To redeem the voucher, the customer must provide a valid PAD birthdate (that is checked against the PAD of the actual OVpay-token and against the voucherClaim provided by the voucher issuer).
                  value:
                    {
                      "voucherDefinitions":
                        [
                          {
                            "productId": 263,
                            "productName": "Voucher Ooievaarspas-product AOW",
                            "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden voor het product \"Ooievaarspas voor AOW-ers in Den Haag\"",
                            "validityPeriod":
                              {
                                "validityPeriodId": 144,
                                "fromInclusive": "2026-01-01T00:00:00.000+00:00",
                                "toInclusive": "2030-12-31T23:59:59.000+00:00",
                              },
                            "productCategory":
                              {
                                "productCategoryId": 9,
                                "isTravelProduct": false,
                                "name": "Voucher",
                              },
                            "requiredProducts":
                              [
                                {
                                  "productId": 982,
                                  "productName": "Ooievaarspas voor AOW-ers in Den Haag",
                                  "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.",
                                },
                              ],
                            "mandatoryCustomerDataItems":
                              [
                                {
                                  "mandatoryCustomerDataItemId": 8,
                                  "customerDataItem": "padBirthDate",
                                }
                              ],
                            "imageReference": "https://www.htm.nl/media/leif2leu/htm-logo-mobile.svg",
                            "termsUrl": "https://www.htm.nl/voorwaarden/vouchers/voucher-xxx-voorwaarden.pdf",
                            "sellingPeriods":
                              [
                                {
                                  "sellingPeriodId": 78,
                                  "fromInclusive": "2026-01-01T00:00:00.000+00:00",
                                  "toInclusive": "2030-12-31T23:59:59.000+00:00",
                                  "salesTouchpoint":
                                    {
                                      "salesTouchpointId": 12,
                                      "name": "Gemeente Den Haag",
                                      "isActive": true,
                                      "retailer":
                                        {
                                          "retailerId": 1001,
                                          "name": "Gemeente Den Haag",
                                          "street": "Koningin Julianaplein",
                                          "number": "10",
                                          "numberAddition": null,
                                          "postalCode": "2595 AA",
                                          "city": "Den Haag",
                                          "country": "Nederland",
                                          "emailAddress": "info@denhaag.nl",
                                          "phoneNumber": "070 374 9002",
                                          "taxId": "572309345923",
                                          "imageReference": "https://www.htm.nl/media/leif2leu/htm-logo-mobile.svg",
                                        },
                                    },
                                  "forbiddenPaymentMethods": [],
                                  "sellingPrices":
                                    [
                                      {
                                        "sellingPriceId": 91,
                                        "amountInclTax": 0,
                                        "fromInclusive": "2026-01-01T00:00:00.000+00:00",
                                        "toInclusive": "2030-12-31T23:59:59.000+00:00",
                                        "internalPrice": 0.0000,
                                        "taxCode": "V09",
                                        "taxPercentage": 9.0000,
                                      }
                                    ]
                                }
                              ]
                          }
                        ]
                    }
        "403":
          description: Forbidden
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Access denied due to insufficient permissions:
                  summary: Access denied due to insufficient permissions
                  value:
                    {
                      "type": "https://example.com/probs/forbidden",
                      "title": "Access denied",
                      "detail": "You do not have permission to access this resource.",
                      "instance": "/voucherdefinitions",
                    }
        "404":
          description: Not found
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Voucher not found:
                  summary: Voucher not found
                  value:
                    {
                      "type": "https://example.com/probs/not-found",
                      "title": "Voucher not found",
                      "detail": "The voucher definition does not exist.",
                      "instance": "/voucherdefinitions",
                    }
        "500":
          description: Internal server error
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Unexpected server error:
                  summary: Unexpected server error
                  value:
                    {
                      "type": "https://example.com/probs/internal-server-error",
                      "title": "Internal Server Error",
                      "detail": "An unexpected error occurred while processing your request.",
                      "instance": "/voucherdefinitions",
                    }
  /issuedvouchers:
    get:
      summary: Get a list of issued vouchers that were issued for a specific touch point
      description:
        Retrieve all issued vouchers for a specific touchpoint. This means that only vouchers that were issued by a touchpoint within the same retailer as the calling touchpoint are returned.
      parameters:
        - name: touchpointId
          in: query
          required: false
          description: |-
            Filter the issued vouchers on a specific touchpointId. This means that only vouchers that were issued by the specified touchpoint are returned.
            This query parameter is only intended for administrative purposes, since the touchpoint associated with the access token used in the request is used to determine which issued vouchers are returned. This query parameter can be used to retrieve issued vouchers for other touchpoints within the same retailer, for example to retrieve issued vouchers for a specific sales touchpoint that is different from the calling touchpoint.
          schema:
            type: integer
            example: 12
        - name: issuedVoucherId
          in: query
          required: false
          description: The unique identifier of the issued voucher instance to retrieve.
          schema:
            type: string
            format: uuid
            example: d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90
        - name: voucherCode
          in: query
          required: false
          description: The unique code (that the customer uses for redeeming the voucher) of the issued voucher to retrieve.
          schema:
            type: string
            example: HTM-A7J-128-PYT
        - name: productId
          in: query
          required: false
          description: Return only issued vouchers that were issued for the given voucher definition (by its productId).
          schema:
            type: integer
            example: 321
        - name: voucherStatusId
          in: query
          required: false
          explode: false
          description: |-
            Return only issued vouchers that currently have the given voucher status(es).
            Possible voucher statuses are:
            - 1 = new
            - 2 = issued
            - 3 = redeemed
            - 4 = revoked
            - 5 = expired
            - 6 = pendingRedemption
          schema:
            type: array
            items:
              type: integer
            example: [4,5]
      tags:
        - Vouchers
      responses:
        "200":
          description: Successful retrieval of voucher instance
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/supplierTouchpointIssuedVouchersListResponse"
              examples:
                List containing one issued voucher that grants a product for free:
                  summary: List containing one issued voucher that grants a product for free
                  description: |-
                   List containing one issued voucher that can be redeemed for the product "Ooievaarspas voor AOW-ers in Den Haag" for free.\
                   In this case, the voucher has an amountInclTax of 0. The requiredProduct also has a sellingPrice of 0, so no "discount" is shown to the customer; just the voucher's amountInclTax.
                   To redeem it, the customer must provide a valid PAD birthdate (that is checked against the PAD of the actual OVpay-token and against the voucherClaim provided by the voucher issuer). The birthdate value that is checked against, can be found in the "voucherClaims" array of the issued voucher.
                  value:
                    {
                      "issuedVouchers":
                        [
                          {
                            "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
                            "voucherCode": "HTM-A7J-128-PYT",
                            "fromInclusive": "2024-10-04T00:00:00.000",
                            "untilInclusive": "2024-11-04T00:00:00.000",
                            "voucherStatus": { "voucherStatusId": 2, "name": "issued" },
                            "product":
                              {
                                "productId": 263,
                                "productName": "Voucher Ooievaarspas-product AOW",
                                "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden voor het product \"Ooievaarspas voor AOW-ers in Den Haag\"",
                                "amountInclTax": 0,
                                "requiredProducts":
                                  [
                                    {
                                      "productId": 982,
                                      "productName": "Ooievaarspas voor AOW-ers in Den Haag",
                                      "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.",
                                      "productCategory": 
                                        {
                                          "productCategoryId": 2,
                                          "isTravelProduct": true,
                                          "name": "Afgekocht reisrecht",
                                        },
                                      "amountInclTax": 0
                                      
                                    },
                                  ],
                                  "_links":
                                    {
                                      "get_voucher_definition_details":
                                        {
                                          "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/voucherdefinitions/263",
                                          "method": "GET",
                                        },
                                    },
                              },
                            "voucherClaims":
                              [
                                {
                                  "mandatoryCustomerDataItem":
                                    {
                                      "mandatoryCustomerDataItemId": 8,
                                      "customerDataItem": "padBirthDate",
                                    },
                                  "value": "1980-06-31",
                                }
                              ]
                          }
                        ]
                    }
                List containing one issued voucher that grants a product for a reduced price:
                  summary: List containing one issued voucher that grants a product for a reduced price
                  description: |-
                   List containing one issued voucher that can be redeemed for the product "Ooievaarspas voor AOW-ers in Den Haag" for a reduced price.\
                   In this case, the voucher has an amountInclTax > 0, which dictates the (modified) total amount that needs to be paid for said product. If the requiredProduct has a non-zero sellingPrice (amountInclTax), the difference between sellingPrice and voucher amountInclTax represents the granted discount. If the requiredProduct has a sellingPrice of 0, no "discount" is shown; just the voucher's amountInclTax.\
                   Specifically, in this example, the product "HTM 20% Korting" can be purchased for 1 euro instead of 5 euro.
                   To redeem it, the customer needs to provide only the voucher code; there are no voucherClaims to be checked against.
                  value:
                    {
                      "issuedVouchers":
                        [
                          {
                            "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
                            "voucherCode": "HTM-A7J-128-PYT",
                            "fromInclusive": "2024-10-04T00:00:00.000",
                            "untilInclusive": "2024-11-04T00:00:00.000",
                            "voucherStatus": { "voucherStatusId": 2, "name": "issued" },
                            "product":
                              {
                                "productId": 264,
                                "productName": "Kortingsvoucher HTM 20% Korting ",
                                "productDescription": "Voucher waarmee het product \"HTM 20% Korting\" voor een lagere prijs kan worden aangeschaft.",
                                "amountInclTax": 100,
                                "requiredProducts":
                                  [
                                    {
                                      "productId": 984,
                                      "productName": "HTM 20% Korting",
                                      "productDescription": "Reis met 20% korting op je betaalpas bij HTM.",
                                      "productCategory": 
                                        {
                                          "productCategoryId": 1,
                                          "isTravelProduct": true,
                                          "name": "Kortingsabonnement",
                                        },
                                      "amountInclTax": 500
                                    }
                                  ],
                                "_links":
                                    {
                                      "get_voucher_definition_details":
                                        {
                                          "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/voucherdefinitions/264",
                                          "method": "GET",
                                        }
                                    }                                  
                              },
                            "voucherClaims":[]
                          },
                        ]
                    }
                List containing one issued voucher that grants a discount for a whole order:
                  summary: List containing one issued voucher that grants a discount for a whole order
                  description: |-
                   List containing one issued voucher that can be redeemed for the product "Ooievaarspas voor AOW-ers in Den Haag" for a reduced price.\
                   In this case, no requiredProduct is specified, and the voucher has an amountInclTax < 0. The (negative) amountInclTax dictates the value of the voucher, that is subtracted from the total order value as a discount (with a minimum order total of 0).
                   To redeem it, the customer needs to provide only the voucher code; there are no voucherClaims to be checked against.
                  value:
                    {
                      "issuedVouchers":
                        [
                          {
                            "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
                            "voucherCode": "HTM-A7J-128-PYT",
                            "fromInclusive": "2024-10-04T00:00:00.000",
                            "untilInclusive": "2024-11-04T00:00:00.000",
                            "voucherStatus": { "voucherStatusId": 2, "name": "issued" },
                            "product":
                              {
                                "productId": 265,
                                "productName": "Voucher 10 euro korting",
                                "productDescription": "Voucher die 10 euro korting geeft op je gehele winkelmand.",
                                "amountInclTax": -1000,
                                "requiredProducts": [],
                                "_links":
                                  {
                                    "get_voucher_definition_details":
                                      {
                                        "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/voucherdefinitions/265",
                                        "method": "GET",
                                      }
                                  }
                              },                                                  
                            "voucherClaims":[]
                          }
                        ]
                    }
        "403":
          description: Forbidden
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Access denied due to insufficient permissions:
                  summary: Access denied due to insufficient permissions
                  value:
                    {
                      "type": "https://example.com/probs/forbidden",
                      "title": "Access denied",
                      "detail": "You do not have permission to access this resource.",
                      "instance": "/issuedvouchers",
                    }
        "404":
          description: Not found
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Voucher not found:
                  summary: Voucher not found
                  value:
                    {
                      "type": "https://example.com/probs/not-found",
                      "title": "Voucher not found",
                      "detail": "The voucher with code VOUCHER123 does not exist.",
                      "instance": "/issuedvouchers",
                    }
        "500":
          description: Internal server error
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Unexpected server error:
                  summary: Unexpected server error
                  value:
                    {
                      "type": "https://example.com/probs/internal-server-error",
                      "title": "Internal Server Error",
                      "detail": "An unexpected error occurred while processing your request.",
                      "instance": "/issuedvouchers",
                    }
    post:
      summary: Issue a voucher for a specific voucher definition
      description: |
        Issue a voucher for a specific voucher definition. Vouchers can only be issued on a one-by-one basis, so that it is always clear what voucher code has been issued for specific voucher claims (which by itself my not uniquely identify the voucher; however the voucher code is guaranteed to be unique). The voucher can only be issued if the calling touchpoint (recognized by the access token) has an active selling period for the voucher definition (recognized by the productId).\
        The \"fromInclusive\" and \"untilInclusive\" fields specify the date-time range in which the voucher can be redeemed by the customer. This has nothing to do with the allowed start date of a requiredProduct (for this, the existing order flow logic is applied).\
        If the voucher definition contains mandatoryCustomerDataItems, a value (to be checked against customer input when redeeming the voucher) has to be provided for each of these items. 
      tags:
        - Vouchers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/supplierTouchpointCreateIssuedVoucherRequest"
            examples:
              Issue a voucher and supply own voucher code:
                summary: Issue a voucher and supply own voucher code
                description: This allows the voucher supplier to supply its own voucher code, which can be useful if the supplier already has its own (internal or external) source for voucher codes. The supplied voucher code must be unique - if this code is already in use, the request will fail.
                value:
                  {
                    "voucherCode": "HTM-A7J-128-PYT",
                    "fromInclusive": "2026-01-01T00:00:00.000+00:00",
                    "untilInclusive": "2030-12-31T23:59:59.000+00:00",
                    "productId": 263,
                    "voucherClaims":
                      [
                        {
                          "mandatoryCustomerDataItemId": 8,
                          "value": "1980-06-31",
                        }
                      ],
                  }
              Issue a voucher and receive a voucher code (generated by ABT backend) in response:
                summary: Issue a voucher and receive a voucher code (generated by ABT backend) in response
                description: If the supplier is not able to generate its own unique voucher codes, it can issue a voucher without supplying any voucher code - the ABT backend will then receive a unique voucher code and return it in response.
                value:
                  {
                    "fromInclusive": "2026-01-01T00:00:00.000+00:00",
                    "untilInclusive": "2030-12-31T23:59:59.000+00:00",
                    "productId": 264
                  }
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/supplierTouchpointIssuedVoucherResponse"
              examples:
                Successfully issued a voucher:
                  summary: Successfully issued a voucher
                  value:
                    {
                      "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
                      "voucherCode": "HTM-A7J-128-PYT",
                      "fromInclusive": "2024-10-04T00:00:00.000",
                      "untilInclusive": "2024-11-04T00:00:00.000",
                      "voucherStatus": { "voucherStatusId": 2, "name": "issued" },
                      "product":
                        {
                          "productId": 263,
                          "productName": "Voucher Ooievaarspas-product AOW",
                          "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden voor het product \"Ooievaarspas voor AOW-ers in Den Haag\"",
                          "amountInclTax": 0,
                          "requiredProducts":
                            [
                              {
                                "productId": 982,
                                "productName": "Ooievaarspas voor AOW-ers in Den Haag",
                                "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.",
                                "productCategory": 
                                  {
                                    "productCategoryId": 2,
                                    "isTravelProduct": true,
                                    "name": "Afgekocht reisrecht",
                                  },
                                "amountInclTax": 0
                                
                              },
                            ],
                            "_links":
                              {
                                "get_voucher_definition_details":
                                  {
                                    "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/voucherdefinitions/263",
                                    "method": "GET",
                                  },
                              },
                        },
                      "voucherClaims":
                        [
                          {
                            "mandatoryCustomerDataItem":
                              {
                                "mandatoryCustomerDataItemId": 8,
                                "customerDataItem": "padBirthDate",
                              },
                            "value": "1980-06-31",
                          }
                        ],
                    }
        "400":
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Voucher code already in use:
                  summary: Voucher code already in use
                  value:
                    {
                      "type": "https://example.com/probs/bad-request",
                      "title": "Invalid voucher code",
                      "detail": "This voucher code is already in use.",
                      "instance": "/issuedvouchers"
                    }
                Missing mandatory voucher claims:
                  summary: Missing mandatory voucher claims
                  value:
                    {
                      "type": "https://example.com/probs/bad-request",
                      "title": "Missing mandatory voucher claims",
                      "detail": "Please provide a value for all mandatoryCustomerDataItems as defined in the voucher definition.",
                      "instance": "/issuedvouchers"
                    }
                Voucher validity period out of allowed range:
                  summary: Voucher validity period out of allowed range
                  value:
                    {
                      "type": "https://example.com/probs/bad-request",
                      "title": "Invalid voucher validity period",
                      "detail": "The validity period of the voucher is outside the allowed range for this voucher definition's sellingPeriod.",
                      "instance": "/issuedvouchers"
                    }

  /issuedvouchers/{issuedVoucherId}:
    parameters:
      - name: issuedVoucherId
        in: path
        required: true
        description: The unique identifier of the issued voucher instance to update the status for.
        schema:
          type: string
          format: uuid
          example: d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90
    patch:
      summary: Update the status of an issued voucher
      description: |-
        Update the status of an issued voucher. Not every state change is allowed; an error will be returned if an invalid state change is attempted.\
        Possible voucher statuses are:
        - 1 = new
        - 2 = issued
        - 3 = redeemed
        - 4 = revoked
        - 5 = expired
        - 6 = pendingRedemption
      tags:
        - Vouchers
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/supplierTouchpointUpdateIssuedVoucherRequest"
            examples:
              Mark a voucher as revoked:
                summary: Mark a voucher as revoked
                value:
                  {
                    "voucherStatusId": 4
                  }
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/supplierTouchpointIssuedVoucherResponse"
              examples:
                Successfully updated the status of a voucher:
                  summary: Successfully updated the status of a voucher
                  value:
                    {
                      "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
                      "voucherCode": "HTM-A7J-128-PYT",
                      "fromInclusive": "2024-10-04T00:00:00.000",
                      "untilInclusive": "2024-11-04T00:00:00.000",
                      "voucherStatus": { "voucherStatusId": 4, "name": "revoked" },
                      "product":
                        {
                          "productId": 263,
                          "productName": "Voucher Ooievaarspas-product AOW",
                          "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden voor het product \"Ooievaarspas voor AOW-ers in Den Haag\"",
                          "amountInclTax": 0,
                          "requiredProducts":
                            [
                              {
                                "productId": 982,
                                "productName": "Ooievaarspas voor AOW-ers in Den Haag",
                                "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.",
                                "productCategory": 
                                  {
                                    "productCategoryId": 2,
                                    "isTravelProduct": true,
                                    "name": "Afgekocht reisrecht",
                                  },
                                "amountInclTax": 0
                              },
                            ],
                            "_links":
                              {
                                "get_voucher_definition_details":
                                  {
                                    "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/voucherdefinitions/263",
                                    "method": "GET",
                                  },
                              },
                        },
                      "voucherClaims":
                        [
                          {
                            "mandatoryCustomerDataItem":
                              {
                                "mandatoryCustomerDataItemId": 8,
                                "customerDataItem": "padBirthDate",
                              },
                            "value": "1980-06-31",
                          }
                        ]
                    }
        "400":
          description: Bad request
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/rfc9457"
              examples:
                Illegal state change:
                  summary: Illegal state change
                  value:
                    {
                      "type": "https://example.com/probs/bad-request",
                      "title": "Bad request",
                      "detail": "This state change is not allowed.",
                      "instance": "/issuedvouchers/d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
                    }
components:
  securitySchemes:
    bearerToken:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    supplierTouchpointVoucherDefinitionsListResponse:
      type: object
      properties:
        voucherDefinitions:
          type: array
          items:
            $ref: "#/components/schemas/supplierTouchpointVoucherDefinitionResponse"
    supplierTouchpointVoucherDefinitionResponse:
      type: object
      required:
        - productId
        - productName
        - productDescription
        - validityPeriod
        - productCategory
        - sellingPeriods
        
      properties:
        productId:
          type: integer
          example: 263
        productName:
          type: string
          example: "Voucher Ooievaarspas-product AOW"
        productDescription:
          type: string
          example: "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden voor het product \"Ooievaarspas voor AOW-ers in Den Haag\""
        validityPeriod:
          type: object
          required:
            - validityPeriodId
            - fromInclusive
            - toInclusive
          properties:
            validityPeriodId:
              type: integer
              example: 1
            fromInclusive:
              type: string
              format: date-time-offset
              example: "2024-09-03T10:01:34.000+00:00"
            toInclusive:
              type: string
              format: date-time-offset
              example: "2024-09-03T23:59:59.999+00:00"
        productCategory:
          type: object
          required:
            - productCategoryId
            - name
            - isTravelProduct
          properties:
            productCategoryId:
              type: integer
              example: 1
            name:
              type: string
              example: Kortingsabonnement
            isTravelProduct:
              type: boolean
              example: true
        requiredProducts:
          type: array
          description: |-
               Currently, only one requiredProduct for vouchers is supported and thus, this array can contain at most one element.
          items:
            type: object
            required:
              - requiredProductId
              - productName
            properties:
              requiredProductId:
                type: integer
                example: 2
              productName:
                type: string
                example: Product name
        mandatoryCustomerDataItems:
          type: array
          items:
            type: object
            required:
              - mandatoryCustomerDataItemId
              - customerDataItem
            properties:
              mandatoryCustomerDataItemId:
                type: integer
                example: 8
              customerDataItem:
                type: string
                example: padBirthdate
        imageReference:
          type: string
          description: Can be a URL or a base64 encoded image
          example: https://htm.azure.net/abt/products/product_1.svg
        termsUrl:
          type: string
          example: https://www.htm.nl/voorwaarden/vouchers/voucher-xxx-voorwaarden.pdf
        sellingPeriods:
          type: array
          items:
            type: object
            required:
              - sellingPeriodId
              - fromInclusive
              - toInclusive
              - salesTouchpoint
            properties:
              sellingPeriodId:
                type: integer
                example: 1
              fromInclusive:
                type: string
                format: date-time-offset
                example: "2022-03-01T00:00:00.000+00:00"
              toInclusive:
                type: string
                format: date-time-offset
                example: "2022-06-01T00:00:00.000+00:00"
              salesTouchpoint:
                type: object
                required:
                  - salesTouchpointId
                  - name
                  - isActive
                  - retailer
                properties:
                  salesTouchpointId:
                    type: integer
                    example: 1
                  name:
                    type: string
                    example: HTM App
                  isActive:
                    type: boolean
                    example: true
                  retailer:
                    type: object
                    required:
                      - retailerId
                      - name
                    properties:
                      retailerId:
                        type: integer
                        example: 1001
                      name:
                        type: string
                        example: HTM
                      street:
                        type: string
                        example: Kon. Julianaplein
                      number:
                        type: string
                        example: "10"
                      numberAddition:
                        type: string
                        example: a
                      postalCode:
                        type: string
                        example: 2595 AA
                      city:
                        type: string
                        example: Den Haag
                      country:
                        type: string
                        example: Nederland
                      emailAddress:
                        type: string
                        format: email
                        example: info@htm.nl
                      phoneNumber:
                        type: string
                        example: "09004864636"
                      taxId:
                        type: string
                        example: "09004864636"
                      imageReference:
                        type: string
                        example: https://htm.azure.net/abt/retailers/htm.svg
              sellingPrices:
                type: array
                items:
                  type: object
                  required:
                  - sellingPriceId
                  - amountInclTax
                  - fromInclusive
                  - toInclusive
                  - internalPrice
                  properties:
                    sellingPriceId:
                      type: integer
                      example: 1
                    taxCode:
                      type: string
                      example: "V09"
                    taxPercentage:
                      type: number
                      example: 9.0000
                    amountInclTax:
                      type: integer
                      example: 908
                    fromInclusive:
                      type: string
                      format: date-time-offset
                      example: "2022-03-01T00:00:00.000+00:00"
                    toInclusive:
                      type: string
                      format: date-time-offset
                      example: "2022-06-01T00:00:00.000+00:00"
                    internalPrice:
                      type: number
                      example: 908.1234
    supplierTouchpointCreateIssuedVoucherRequest:
      type: object
      required:
        - fromInclusive
        - untilInclusive
        - productId
      properties:
        voucherCode:
          type: string
          description: The voucher code that is shared with the customer and uniquely identifies this voucher. When not provided, a random voucher code will be generated by the backend system and returned in the response.
          example: "HTM-A7J-128-PYT"
        fromInclusive:
          type: string
          format: date-time-offset
          description: |-
           The date and time the voucher becomes valid for redemption. This has nothing to do with 
           the allowed start date of a requiredProduct (for this, the existing order flow logic is applied).
          example: "2024-10-04T00:00:00.000+02:00"
        untilInclusive:
          type: string
          format: date-time-offset
          description: |-
           The date and time the voucher becomes invalid for redemption. This has nothing to do with 
           the maximum allowed start date of a requiredProduct (for this, the existing order flow logic is applied).
          example: "2024-11-04T00:00:00.000+01:00"
        productId:
          type: integer
          description: The productId for the voucher definition for which this voucher instance is issued.
          example: 263
        voucherClaims:
          type: array
          items:
            type: object
            required:
              - mandatoryCustomerDataItemId
              - value
            properties:
              mandatoryCustomerDataItemId:
                type: integer
                description: The mandatoryCustomerDataItemId for the mandatoryCustomerDataItem for which this value is provided.
                example: 8
              value:
                type: string
                description: The value that the customer must provide for this mandatoryCustomerDataItem to be able to redeem the voucher.
                example: "1970-01-01"
    supplierTouchpointUpdateIssuedVoucherRequest:
      type: object
      required:
        - voucherStatusId
      properties:
        voucherStatusId:
          type: integer
          description: The new status of the voucher.
          example: 4
    supplierTouchpointIssuedVouchersListResponse:
      type: object
      properties:
        issuedVouchers:
          type: array
          items:
            $ref: "#/components/schemas/supplierTouchpointIssuedVoucherResponse"
    supplierTouchpointIssuedVoucherResponse:
      type: object
      required:
        - issuedVoucherId
        - voucherCode
        - fromInclusive
        - untilInclusive
        - voucherStatus
        - product
        - mandatoryCustomerDataItems
      properties:
        issuedVoucherId:
          type: string
          description: The unique (technical) identifier of the issued voucher instance.
          example: "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90"
        voucherCode:
          type: string
          description: The voucher code that is shared with the customer and uniquely identifies this voucher.
          example: "HTM-A7J-128-PYT"
        fromInclusive:
          type: string
          format: date-time-offset
          description: |-
            The date and time the voucher becomes valid for redemption. This has nothing to do with 
            the allowed start date of a requiredProduct (for this, the existing order flow logic is applied).
          example: "2024-10-04T00:00:00.000+02:00"
        untilInclusive:
          type: string
          format: date-time-offset
          description: |-
            The date and time the voucher becomes invalid for redemption. This has nothing to do with 
            the maximum allowed start date of a requiredProduct (for this, the existing order flow logic is applied).
          example: "2024-11-04T00:00:00.000+01:00"
        voucherStatus:
          type: object
          required:
            - voucherStatusId
            - name
          description: |-
            The current status of the voucher. Can be any of the following:
            - 1 = new
            - 2 = issued
            - 3 = redeemed
            - 4 = revoked
            - 5 = expired
            - 6 = pendingRedemption
          properties:
            voucherStatusId:
              type: integer
              example: 2
            name:
              type: string
              example: "issued"
        product:
          type: object
          description: The "product" referencing the voucher definition that this voucher instance is based on
          required:
            - productId
            - productName
            - productDescription
            - amountInclTax
          properties:
            productId:
              type: integer
              example: 263
            productName:
              type: string
              example: Voucher Ooievaarspas-product AOW
            productDescription:
              type: string
              example: |-
                Voucher voor AOW-ers in Den Haag met een Ooievaarspas, die ingewisseld kan worden 
                voor het product "Ooievaarspas voor AOW-ers in Den Haag".
            amountInclTax:
              type: integer
              description: |- 
                When combined with a requiredProduct, the (positive or zero) amountInclTax dictates 
                the (modified) total amount that needs to be paid for said product. When the requiredProduct 
                has a sellingPrice > 0, the difference between sellingPrice and voucher amountInclTax
                represents the granted discount.
                When not combined with a required product, the (negative) amountInclTax dictates
                the value of the voucher, that is subtracted from the total order value as a discount 
                (with a minimum order total of 0).
              example: 0
            requiredProducts:
              type: array
              description: |-
                Currently, only one requiredProduct is supported and thus, this array can contain at 
                most one element.
              items:
                type: object
                required:
                  - productId                 
                properties:
                  productId:
                    type: integer
                    example: 892
                  productName:
                    type: string
                    example: "Ooievaarspas voor AOW-ers in Den Haag"
                  productDescription:
                    type: string
                    example: "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas."
                  productCategory:
                    type: object
                    required: 
                      - productCategoryId
                      - isTravelProduct
                      - name
                    properties:
                      productCategoryId:
                        type: integer
                        example: 2
                      isTravelProduct:
                        type: boolean
                        example: true
                      name:
                        type: string
                        example: "Afgekocht reisrecht"
                  amountInclTax:
                    type: integer
                    description: |-
                      Selling price of the product in cents (including tax, if applicable) that is 
                      currently active for the calling touchpoint. When 0, the product is free of charge.
                    example: 0
                  imageReference:
                    type: string
                    description: Can be a URL or a base64 encoded image
                    example: https://www.htm.nl/nog-onbekende-productafbeelding                  
            _links:
              type: object
              properties:
                get_voucher_definition_details:
                  type: object
                  description: Link to get more details for the voucher definition that this voucher is instanced from
                  properties:
                    href:
                      type: string
                      example: https://api.integratielaag.nl/abt/touchpoint/1.0/voucherdefinitions/263
                    method:
                      type: string
                      example: GET
        voucherClaims:
          type: array
          description: |-
            List of pairs, each containing a mandatoryCustomerDataItem and the value that the customer must provide for this mandatoryCustomerDataItem to be able to redeem the voucher. 
            The values to be checked against are provided by the voucher issuer/supplier.
          items: 
            type: object
            required:
              - mandatoryCustomerDataItem
              - value
            properties:
              mandatoryCustomerDataItem:
                type: object
                required:
                  - mandatoryCustomerDataItemId
                  - customerDataItem
                properties:
                  mandatoryCustomerDataItemId:
                    type: integer
                    example: 8
                  customerDataItem:
                    type: string
                    example: padBirthdate
              value:
                type: string
                example: 1970-01-01
              
    unavailable:
      type: object
    rfc9457:
      type: object
      properties:
        type:
          type: string
          format: url
          example: https://example.com/probs/out-of-credit
        title:
          type: string
          example: You do not have enough credit.
        detail:
          type: string
          example: Your current balance is 30, but that costs 50.
        instance:
          type: string
          example: /account/12345/msgs/abc
        balance:
          type: string
          example: 30
        accounts:
          type: array
          items:
            type: string
            example:
              - /account/12345
              - /account/67890
