From 9fb20a491f97e18dbd7637caf299dc53757d1b6c Mon Sep 17 00:00:00 2001 From: Max Martens Date: Wed, 6 May 2026 08:28:21 +0200 Subject: [PATCH 1/7] WIP update spec with examples for Ooievaarspas-AOW (still need to finish POST/PATCH) --- .../products/SE-vouchers-supplier.yaml | 175 +++++++----------- 1 file changed, 70 insertions(+), 105 deletions(-) diff --git a/src/openapi/products/SE-vouchers-supplier.yaml b/src/openapi/products/SE-vouchers-supplier.yaml index 2ed5e39..5328410 100644 --- a/src/openapi/products/SE-vouchers-supplier.yaml +++ b/src/openapi/products/SE-vouchers-supplier.yaml @@ -1,7 +1,7 @@ openapi: 3.0.1 info: title: Service Engine APIs for HTM voucher suppliers - description: Service Engine APIs for HTM vouchers 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. + 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 @@ -10,32 +10,39 @@ paths: get: tags: - Vouchers - summary: Get a list of all voucher definitions that a touch point is allowed to issue + 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 touch point is allowed to issue. - Essentially, this means that only products that have active sellingPeriods for touch points within the same - retailer as the calling touch point are returned. + 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 + - Most other attributes are also prerequisites for redeeming the voucher, but they will likely match the attributes of the product that is acquired when redeeming the voucher (voucher requires PAD attributes if the product requires PAD attributes, etc.) parameters: - name: touchpointId in: query required: false description: | - Filter the voucher definitions on a specific touch point id. This means that only voucher definitions with active selling periods for the specified touch point are returned. - This query parameter is only intended for administrative purposes, since the touch point 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 touch points within the same retailer, for example to retrieve voucher definitions for a specific sales touch point that is different from the calling touch point. + 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: 1001 + example: 8 - name: productId in: query required: false - description: Filter the voucher definitions on a specific product id. + description: Return a specific voucher definition by it's productId. schema: type: integer - example: 263 + example: 321 - name: requiredProductId in: query required: false - description: Filter the voucher definitions on a specific required product id. This means that only voucher definitions that have the specified product id in their requiredProducts list are returned. + 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 @@ -58,22 +65,24 @@ paths: summary: No products / Empty list description: No products value: { "voucherDefinitions": [] } - List containing one voucher definition (called by touchpointId 1001): - summary: List containing one voucher definition (called by touchpointId 10010011) - description: TODO + List containing one voucher definition (called by touchpointId 8): + summary: List containing one voucher definition (called by touchpointId 8) + description: |- + List containing one voucher definition for a voucher that can be redeemed for the product "Ooievaarspas voor AOW-ers in Den Haag".\ + To redeem it, the customer must provide a valid PAD birth date (that is checked against the PAD of the actual OVpay-token and against the voucherClaim provided by the voucher issuer). value: { "voucherDefinitions": [ { - "productId": 1002, - "productName": "Korting Ooievaarspas", - "productDescription": "Kortingsvoucher voor houders van een Ooievaarspas", + "productId": 321, + "productName": "Voucher Ooievaarspas-product AOW", + "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, dat recht geeft op het product \"Ooievaarspas voor AOW-ers in Den Haag\"", "validityPeriod": { "validityPeriodId": 144, - "fromInclusive": "2023-12-31T23:00:00.000+00:00", - "toInclusive": "2028-11-25T04:00:00.000+00:00", + "fromInclusive": "2026-01-01:00:00.000+00:00", + "toInclusive": "2030-12-31T023:59:59.000+00:00", }, "productCategory": { @@ -85,8 +94,8 @@ paths: [ { "productId": 126, - "productName": "HTM-30001", - "productDescription": "Reis met 20% korting op je betaalpas bij HTM.", + "productName": "Ooievaarspas voor AOW-ers in Den Haag", + "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.", }, ], "mandatoryCustomerDataItems": @@ -94,11 +103,7 @@ paths: { "mandatoryCustomerDataItemId": 8, "customerDataItem": "padBirthDate", - }, - { - "mandatoryCustomerDataItemId": 4, - "customerDataItem": "emailAddress", - }, + } ], "imageReference": "https://www.htm.nl/media/leif2leu/htm-logo-mobile.svg", "productPageUrl": "https://www.htm.nl/nog-onbekende-product-pagina", @@ -106,11 +111,11 @@ paths: [ { "sellingPeriodId": 78, - "fromInclusive": "2024-09-30T23:00:00.000+00:00", - "toInclusive": "2028-11-17T23:00:00.000+00:00", + "fromInclusive": "2026-01-01:00:00.000+00:00", + "toInclusive": "2030-12-31T023:59:59.000+00:00", "salesTouchpoint": { - "salesTouchpointId": 1001, + "salesTouchpointId": 8, "name": "Gemeente Den Haag", "isActive": true, "retailer": @@ -133,11 +138,10 @@ paths: "sellingPrices": [ { - "sellingPriceId": 78, - "amountExclTax": null, - "amountInclTax": -100, - "fromInclusive": "2024-09-30T23:00:00.000+00:00", - "toInclusive": "2028-11-17T23:00:00.000+00:00", + "sellingPriceId": 91, + "amountInclTax": 0, + "fromInclusive": "2026-01-01:00:00.000+00:00", + "toInclusive": "2030-12-31T023:59:59.000+00:00", "internalPrice": 0.0000, "taxCode": "V09", "taxPercentage": 9.0000, @@ -200,18 +204,17 @@ paths: get: summary: Get a list of issued vouchers that were issued for a specific touch point description: - Retrieve all issued vouchers for a specific touch point. This means that only products that have active sellingPeriods for touch points within the same - retailer as the calling touch point are returned. + 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 touch point id. This means that only issued vouchers for products with active selling periods for the specified touch point are returned. - This query parameter is only intended for administrative purposes, since the touch point 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 touch points within the same retailer, for example to retrieve issued vouchers for a specific sales touch point that is different from the calling touch point. + 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: 1001 + example: 8 - name: issuedVoucherId in: query required: false @@ -223,14 +226,14 @@ paths: - name: voucherCode in: query required: false - description: The unique code of the issued voucher to retrieve. + description: The unique code (that the customer uses for redeeming the voucher) of the issued voucher to retrieve. schema: type: string - example: VOUCHER123 + example: HTM-A7J-128-PYT - name: productId in: query required: false - description: The unique identifier of the product for which to retrieve all issued vouchers. + description: Return only vouchers that were issued for the given voucher definition (by it's productId). schema: type: integer example: 263 @@ -245,6 +248,7 @@ paths: - 3 = redeemed - 4 = revoked - 5 = expired + - 6 = pendingRedemption schema: type: array items: @@ -260,37 +264,45 @@ paths: schema: $ref: "#/components/schemas/unavailable" examples: - Voucher for a product with required attributes: - summary: Voucher for a single product with required attributes + List containing one issued voucher: + summary: List containing one issued voucher + description: |- + List containing one issued voucher that can be redeemed for the product "Ooievaarspas voor AOW-ers in Den Haag".\ + To redeem it, the customer must provide a valid PAD birth date (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 "claims" array of the issued voucher. value: { "issuedVouchers": [ { "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", - "voucherCode": "VOUCHER123", - "fromInclusive": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", + "voucherCode": "HTM-A7J-128-PYT", + "fromInclusive": "2026-01-01:00:00.000+00:00", + "untilInclusive": "2030-12-31T023:59:59.000+00:00", "voucherStatus": { "voucherStatusId": 1, "name": "New" }, "product": { - "productId": 263, - "productName": "HTM-80001", - "productDescription": "10 euro korting op Regiovrij maand.", + "productId": 321, + "productName": "Voucher Ooievaarspas-product AOW", + "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, dat recht geeft op het product \"Ooievaarspas voor AOW-ers in Den Haag\"", + "validityPeriod": + { + "validityPeriodId": 144, + "fromInclusive": "2026-01-01:00:00.000+00:00", + "toInclusive": "2030-12-31T023:59:59.000+00:00", + }, "productCategory": { "productCategoryId": 9, "isTravelProduct": false, "name": "Voucher", }, - "amountInclTax": -1000, "requiredProducts": [ { "productId": 126, - "productName": "HTM-30001", - "productDescription": "Regiovrij maand.", + "productName": "Ooievaarspas voor AOW-ers in Den Haag", + "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.", "_links": { "get_details": @@ -298,14 +310,14 @@ paths: "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/126", "method": "GET", }, - }, - }, + } + } ], "_links": { "get_details": { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263", + "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/321", "method": "GET", }, }, @@ -319,58 +331,11 @@ paths: "customerDataItem": "padBirthDate", }, "value": "1980-06-31", - }, - { - "mandatoryCustomerDataItem": - { - "mandatoryCustomerDataItemId": 4, - "customerDataItem": "emailAddress", - }, - "value": "harry@griffindor.co.uk", - }, + } ], }, ], } - Voucher for a whole order: - summary: Voucher for a whole order - value: - { - "issuedVouchers": - [ - { - "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", - "voucherCode": "VOUCHER123", - "fromInclusive": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", - "voucherStatus": - { "voucherStatusId": 1, "name": "New" }, - "product": - { - "productId": 263, - "productName": "HTM-80002", - "productDescription": "10 euro korting op je gehele winkelmand.", - "productCategory": - { - "productCategoryId": 9, - "isTravelProduct": false, - "name": "Voucher", - }, - "amountInclTax": -1000, - "requiredProducts": [], - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263", - "method": "GET", - }, - }, - }, - }, - "claims": [], - ], - } "403": description: Forbidden content: From 69908f58b06226014f98b792bd9f8921311fd842 Mon Sep 17 00:00:00 2001 From: Max Martens Date: Wed, 6 May 2026 22:44:55 +0200 Subject: [PATCH 2/7] Finished updating, will be shared with pass devs in this state - I tweaked some stuff, needs to be discussed if this is final desired spec, but good enough to give pass devs a general idea --- .../products/SE-vouchers-supplier.yaml | 238 ++++++++---------- 1 file changed, 110 insertions(+), 128 deletions(-) diff --git a/src/openapi/products/SE-vouchers-supplier.yaml b/src/openapi/products/SE-vouchers-supplier.yaml index 5328410..9df5ea1 100644 --- a/src/openapi/products/SE-vouchers-supplier.yaml +++ b/src/openapi/products/SE-vouchers-supplier.yaml @@ -31,7 +31,7 @@ paths: 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: 8 + example: 12 - name: productId in: query required: false @@ -65,11 +65,11 @@ paths: summary: No products / Empty list description: No products value: { "voucherDefinitions": [] } - List containing one voucher definition (called by touchpointId 8): - summary: List containing one voucher definition (called by touchpointId 8) + 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".\ - To redeem it, the customer must provide a valid PAD birth date (that is checked against the PAD of the actual OVpay-token and against the voucherClaim provided by the voucher issuer). + 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). value: { "voucherDefinitions": @@ -77,12 +77,12 @@ paths: { "productId": 321, "productName": "Voucher Ooievaarspas-product AOW", - "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, dat recht geeft op het product \"Ooievaarspas voor AOW-ers in Den Haag\"", + "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-01:00:00.000+00:00", - "toInclusive": "2030-12-31T023:59:59.000+00:00", + "fromInclusive": "2026-01-01T00:00:00.000+00:00", + "toInclusive": "2030-12-31T23:59:59.000+00:00", }, "productCategory": { @@ -111,11 +111,11 @@ paths: [ { "sellingPeriodId": 78, - "fromInclusive": "2026-01-01:00:00.000+00:00", - "toInclusive": "2030-12-31T023:59:59.000+00:00", + "fromInclusive": "2026-01-01T00:00:00.000+00:00", + "toInclusive": "2030-12-31T23:59:59.000+00:00", "salesTouchpoint": { - "salesTouchpointId": 8, + "salesTouchpointId": 12, "name": "Gemeente Den Haag", "isActive": true, "retailer": @@ -140,8 +140,8 @@ paths: { "sellingPriceId": 91, "amountInclTax": 0, - "fromInclusive": "2026-01-01:00:00.000+00:00", - "toInclusive": "2030-12-31T023:59:59.000+00:00", + "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, @@ -214,7 +214,7 @@ paths: 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: 8 + example: 12 - name: issuedVoucherId in: query required: false @@ -236,7 +236,7 @@ paths: description: Return only vouchers that were issued for the given voucher definition (by it's productId). schema: type: integer - example: 263 + example: 321 - name: highestVoucherStatusId in: query required: false @@ -250,10 +250,8 @@ paths: - 5 = expired - 6 = pendingRedemption schema: - type: array - items: - type: integer - example: [1, 2] + type: integer + example: 3 tags: - Vouchers responses: @@ -268,7 +266,7 @@ paths: summary: List containing one issued voucher description: |- List containing one issued voucher that can be redeemed for the product "Ooievaarspas voor AOW-ers in Den Haag".\ - To redeem it, the customer must provide a valid PAD birth date (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 "claims" array of the issued voucher. + 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 "claims" array of the issued voucher. value: { "issuedVouchers": @@ -276,51 +274,23 @@ paths: { "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", "voucherCode": "HTM-A7J-128-PYT", - "fromInclusive": "2026-01-01:00:00.000+00:00", - "untilInclusive": "2030-12-31T023:59:59.000+00:00", + "fromInclusive": "2026-01-01T00:00:00.000+00:00", + "untilInclusive": "2030-12-31T23:59:59.000+00:00", "voucherStatus": { "voucherStatusId": 1, "name": "New" }, "product": { "productId": 321, "productName": "Voucher Ooievaarspas-product AOW", - "productDescription": "Voucher voor AOW-ers in Den Haag met een Ooievaarspas, dat recht geeft op het product \"Ooievaarspas voor AOW-ers in Den Haag\"", - "validityPeriod": - { - "validityPeriodId": 144, - "fromInclusive": "2026-01-01:00:00.000+00:00", - "toInclusive": "2030-12-31T023:59:59.000+00:00", - }, - "productCategory": - { - "productCategoryId": 9, - "isTravelProduct": false, - "name": "Voucher", - }, + "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\"", "requiredProducts": [ { "productId": 126, "productName": "Ooievaarspas voor AOW-ers in Den Haag", - "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.", - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/126", - "method": "GET", - }, - } + "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas." } - ], - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/321", - "method": "GET", - }, - }, + ] }, "claims": [ @@ -385,10 +355,9 @@ paths: "instance": "/issuedvouchers", } post: - summary: Issue a voucher for a specific product + summary: Issue a voucher for a specific voucher definition description: | - Issue a voucher for a specific product. The voucher will be issued for the touch point that is associated with the access token used in the request. - The product for which the voucher should be issued must have active selling periods for touch points within the same retailer as the calling touch point. + 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). tags: - Vouchers requestBody: @@ -398,43 +367,37 @@ paths: schema: $ref: "#/components/schemas/unavailable" examples: - Issue a voucher with prefilled voucher code: - summary: Issue a voucher with prefilled voucher code + 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 suplier 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": "VOUCHER123", - "fromInclusive": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", - "productId": 263, + "voucherCode": "HTM-A7J-128-PYT", + "fromInclusive": "2026-01-01T00:00:00.000+00:00", + "untilInclusive": "2030-12-31T23:59:59.000+00:00", + "productId": 321, "voucherClaims": [ { "mandatoryCustomerDataItemId": 8, - "value": "1970-01-01", - }, - { - "mandatoryCustomerDataItemId": 4, - "value": "stasjo@html.nl", - }, + "value": "1980-06-31", + } ], } - Issue a voucher without prefilled voucher code: - summary: Issue a voucher without prefilled voucher code + 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": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", - "productId": 263, + "fromInclusive": "2026-01-01T00:00:00.000+00:00", + "untilInclusive": "2030-12-31T23:59:59.000+00:00", + "productId": 321, "voucherClaims": [ { "mandatoryCustomerDataItemId": 8, - "value": "1970-01-01", - }, - { - "mandatoryCustomerDataItemId": 4, - "value": "stasjo@html.nl", - }, + "value": "1980-06-31", + } ], } responses: @@ -450,33 +413,36 @@ paths: value: { "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", - "voucherCode": "HKV-A7J-128-PYT", - "fromInclusive": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", + "voucherCode": "HTM-A7J-128-PYT", + "fromInclusive": "2026-01-01T00:00:00.000+00:00", + "untilInclusive": "2030-12-31T23:59:59.000+00:00", "voucherStatus": { "voucherStatusId": 1, "name": "New" }, "product": { - "productId": 263, - "productName": "HTM-80002", - "productDescription": "10 euro korting op je gehele winkelmand.", - "productCategory": - { - "productCategoryId": 9, - "isTravelProduct": false, - "name": "Voucher", - }, - "amountInclTax": -1000, - "requiredProducts": [], - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263", - "method": "GET", - }, - }, + "productId": 321, + "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\"", + "requiredProducts": + [ + { + "productId": 126, + "productName": "Ooievaarspas voor AOW-ers in Den Haag", + "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas." + } + ] }, - } + "claims": + [ + { + "mandatoryCustomerDataItem": + { + "mandatoryCustomerDataItemId": 8, + "customerDataItem": "padBirthDate", + }, + "value": "1980-06-31", + } + ] + } /issuedvouchers/{issuedVoucherId}: parameters: - name: issuedVoucherId @@ -489,7 +455,15 @@ paths: example: d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90 patch: summary: Update the status of an issued voucher - description: Update the status of an issued voucher. This can be used to mark a voucher as redeemed, revoked or expired. + 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: @@ -500,10 +474,10 @@ paths: $ref: "#/components/schemas/unavailable" examples: Mark a voucher as expired: - summary: Mark a voucher as expired + summary: Mark a voucher as revoked value: { - "voucherStatusId": 5, + "voucherStatusId": 4, } responses: "200": @@ -518,32 +492,40 @@ paths: value: { "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", - "voucherCode": "HKV-A7J-128-PYT", - "fromInclusive": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", - "voucherStatus": { "voucherStatusId": 5, "name": "Expired" }, + "voucherCode": "HTM-A7J-128-PYT", + "fromInclusive": "2026-01-01T00:00:00.000+00:00", + "untilInclusive": "2030-12-31T23:59:59.000+00:00", + "voucherStatus": { "voucherStatusId": 4, "name": "Revoked" }, "product": { - "productId": 263, - "productName": "HTM-80002", - "productDescription": "10 euro korting op je gehele winkelmand.", - "productCategory": - { - "productCategoryId": 9, - "isTravelProduct": false, - "name": "Voucher", - }, - "amountInclTax": -1000, - "requiredProducts": [], - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263", - "method": "GET", - }, - }, - }, + "productId": 321, + "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\"", + "requiredProducts": + [ + { + "productId": 126, + "productName": "Ooievaarspas voor AOW-ers in Den Haag", + "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas." + } + ] + } + } + "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: From f8010560cccf892211dcc9427c120d9e2a9b8895 Mon Sep 17 00:00:00 2001 From: Max Martens Date: Thu, 7 May 2026 09:52:29 +0200 Subject: [PATCH 3/7] Tweak query param --- src/openapi/products/SE-vouchers-supplier.yaml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/openapi/products/SE-vouchers-supplier.yaml b/src/openapi/products/SE-vouchers-supplier.yaml index 9df5ea1..c284f82 100644 --- a/src/openapi/products/SE-vouchers-supplier.yaml +++ b/src/openapi/products/SE-vouchers-supplier.yaml @@ -233,25 +233,26 @@ paths: - name: productId in: query required: false - description: Return only vouchers that were issued for the given voucher definition (by it's productId). + description: Return only issued vouchers that were issued for the given voucher definition (by it's productId). schema: type: integer example: 321 - - name: highestVoucherStatusId + - name: voucherStatusId in: query required: false explode: false description: |- - The highest voucher status id to filter the issued vouchers on. - - 1 = new + Return only issued vouchers that currently have the given voucher status(es). - 2 = issued - 3 = redeemed - 4 = revoked - 5 = expired - 6 = pendingRedemption schema: - type: integer - example: 3 + type: array + items: + type: integer + example: [4,5] tags: - Vouchers responses: From a09ad1ad083de2b61cf024bca8012aaa22b1f711 Mon Sep 17 00:00:00 2001 From: Max Martens Date: Mon, 1 Jun 2026 10:40:28 +0200 Subject: [PATCH 4/7] Process PR feedback, first version of issuedVoucher JSON schema --- src/openapi/products/SE-vouchers-TP.yaml | 254 +++++++++++------- .../products/SE-vouchers-supplier.yaml | 6 +- 2 files changed, 164 insertions(+), 96 deletions(-) diff --git a/src/openapi/products/SE-vouchers-TP.yaml b/src/openapi/products/SE-vouchers-TP.yaml index 8b8c724..ef6ba2f 100644 --- a/src/openapi/products/SE-vouchers-TP.yaml +++ b/src/openapi/products/SE-vouchers-TP.yaml @@ -28,99 +28,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/unavailable" - examples: - Voucher for a product with required attributes: - summary: Voucher for a single product with required attributes - value: - { - "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", - "voucherCode": "VOUCHER123", - "fromInclusive": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", - "voucherStatus": { "voucherStatusId": 1, "name": "New" }, - "product": - { - "productId": 263, - "productName": "HTM-80001", - "productDescription": "10 euro korting op Regiovrij maand.", - "productCategory": - { - "productCategoryId": 9, - "isTravelProduct": false, - "name": "Voucher", - }, - "amountInclTax": -1000, - "requiredProducts": - [ - { - "productId": 126, - "productName": "HTM-30001", - "productDescription": "Regiovrij maand.", - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/126", - "method": "GET", - }, - }, - }, - ], - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263", - "method": "GET", - }, - }, - }, - "mandatoryCustomerDataItems": - [ - { - "mandatoryCustomerDataItemId": 8, - "customerDataItem": "padBirthDate", - }, - { - "mandatoryCustomerDataItemId": 4, - "customerDataItem": "emailAddress", - }, - ], - } - Voucher for a whole order: - summary: Voucher for a whole order - value: - { - "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", - "voucherCode": "VOUCHER123", - "fromInclusive": "2024-10-04T00:00:00.000", - "untilInclusive": "2024-11-04T00:00:00.000", - "voucherStatus": { "voucherStatusId": 1, "name": "New" }, - "product": - { - "productId": 263, - "productName": "HTM-80002", - "productDescription": "10 euro korting op je gehele winkelmand.", - "productCategory": - { - "productCategoryId": 9, - "isTravelProduct": false, - "name": "Voucher", - }, - "amountInclTax": -1000, - "requiredProducts": [], - "_links": - { - "get_details": - { - "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/263", - "method": "GET", - }, - }, - }, - "mandatoryCustomerDataItems": [], - } + $ref: "#/components/schemas/issuedVoucherResponse" "403": description: Forbidden content: @@ -176,6 +84,166 @@ components: scheme: bearer bearerFormat: JWT schemas: + issuedVoucherResponse: + 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 + 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" + untilInclusive: + type: string + format: date-time + 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" + 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 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_details: + type: object + description: Link to get more details for the product that this voucher instance applies to + properties: + href: + type: string + example: https://api.integratielaag.nl/abt/touchpoint/1.0/products/982 + method: + type: string + example: GET + mandatoryCustomerDataItems: + type: array + description: |- + List of mandatory customer data items that are required to redeem this voucher.\ + The values provided for these data items may be checked against allowed values as provided by the voucher issuer. + items: + type: object + required: + - mandatoryCustomerDataItemId + - customerDataItem + properties: + mandatoryCustomerDataItemId: + type: integer + example: 8 + customerDataItem: + type: string + example: padBirthdate + unavailable: type: object rfc9457: diff --git a/src/openapi/products/SE-vouchers-supplier.yaml b/src/openapi/products/SE-vouchers-supplier.yaml index c284f82..5b1aa2b 100644 --- a/src/openapi/products/SE-vouchers-supplier.yaml +++ b/src/openapi/products/SE-vouchers-supplier.yaml @@ -35,7 +35,7 @@ paths: - name: productId in: query required: false - description: Return a specific voucher definition by it's productId. + description: Return a specific voucher definition by its productId. schema: type: integer example: 321 @@ -233,7 +233,7 @@ paths: - name: productId in: query required: false - description: Return only issued vouchers that were issued for the given voucher definition (by it's productId). + description: Return only issued vouchers that were issued for the given voucher definition (by its productId). schema: type: integer example: 321 @@ -370,7 +370,7 @@ paths: 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 suplier 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. + 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", From 7173bd3727cf77cea0f0fef35f646031435759f4 Mon Sep 17 00:00:00 2001 From: Max Martens Date: Mon, 1 Jun 2026 11:17:22 +0200 Subject: [PATCH 5/7] Finished JSON schema and all 3 relevant examples for TP vouchers OpenAPI spec (will also update vouchers supplier OpenAPI spec soon) --- src/openapi/products/SE-vouchers-TP.yaml | 125 ++++++++++++++++++++++- 1 file changed, 122 insertions(+), 3 deletions(-) diff --git a/src/openapi/products/SE-vouchers-TP.yaml b/src/openapi/products/SE-vouchers-TP.yaml index ef6ba2f..ebd38f3 100644 --- a/src/openapi/products/SE-vouchers-TP.yaml +++ b/src/openapi/products/SE-vouchers-TP.yaml @@ -28,7 +28,126 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/issuedVoucherResponse" + $ref: "#/components/schemas/issuedVoucherResponse" + examples: + Voucher that grants a voucher-only product for free: + summary: Voucher that grants a voucher-only product for free + description: |- + Voucher that grants a product (that can onlu be acquired via a voucher) for free. + In this case, the voucher has an amountInclTax of 0. 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. + 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.", + "_links": + { + "get_details": + { + "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/982", + "method": "GET", + }, + }, + }, + ] + }, + "mandatoryCustomerDataItems": + [ + { + "mandatoryCustomerDataItemId": 8, + "customerDataItem": "padBirthDate" + } + ] + } + Voucher that grants a hybrid product for a reduced price: + summary: Voucher that grants a hybrid product for a reduced price + description: |- + Voucher that grants a hybrid product (that can be acquired via voucher or via ordinary order flow) + 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. + 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": 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_details": + { + "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/products/984", + "method": "GET", + }, + }, + }, + ] + }, + "mandatoryCustomerDataItems": [] + } + Voucher that grants a discount for a whole order: + summary: Voucher that grants a discount for a whole order + description: |- + Voucher that grants a discount for a whole order. 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). + 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": 265, + "productName": "Voucher 10 euro korting", + "productDescription": "Voucher die10 euro korting geeft op je gehele winkelmand.", + "amountInclTax": -1000, + "requiredProducts": [] + }, + "mandatoryCustomerDataItems": [] + } "403": description: Forbidden content: @@ -161,8 +280,8 @@ components: type: integer description: |- When combined with a requiredProduct, the (positive or zero) amountInclTax dictates - the total amount that needs to be paid for said product. When the requiredProduct has - a sellingPrice > 0, the difference between sellingPrice and voucher amountInclTax + 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 From 531eaa2ff679a7d3fd57aea978b556f5dddd51a0 Mon Sep 17 00:00:00 2001 From: Max Martens Date: Tue, 2 Jun 2026 15:21:03 +0000 Subject: [PATCH 6/7] Update src/openapi/products/SE-vouchers-TP.yaml Fix some typos Signed-off-by: Max Martens --- src/openapi/products/SE-vouchers-TP.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/openapi/products/SE-vouchers-TP.yaml b/src/openapi/products/SE-vouchers-TP.yaml index ebd38f3..cbab308 100644 --- a/src/openapi/products/SE-vouchers-TP.yaml +++ b/src/openapi/products/SE-vouchers-TP.yaml @@ -1,17 +1,17 @@ openapi: 3.0.1 info: - title: Service Engine APIs for HTM voucher for sales Touchpint - description: Service Engine APIs for HTM vouchers. These are NOT the CRUD APIs to the data hub. These ARE the api's for sales touchpoints. + title: Service Engine APIs for HTM voucher for sales Touchpoint + description: Service Engine APIs for HTM vouchers. These are NOT the CRUD APIs to the data hub. These ARE the APIs for sales touchpoints. version: "1.0" servers: - url: https://services.acc.api.htm.nl/abt/abtvouchersTouchpoint/1.0 paths: /issuedvouchers/{voucherCode}: get: - summary: Get details of a voucher, that was issued for a specific touch point + summary: Get details of a voucher, that was issued for a specific touchpoint description: - Get details of an issued voucher for a specific touch point. This means that only products that the calling touch point is allowed to see or sell - (i.e. has active sellingPeriods for touchPointId of the calling touch point) are returned. + Get details of an issued voucher for a specific touchpoint. This means that only products that the calling touchpoint is allowed to see or sell + (i.e. has active sellingPeriods for touchPointId of the calling touchpoint) are returned. parameters: - name: voucherCode in: path From bd870d0fa8b19412b74fcd507501a97cab7c0c02 Mon Sep 17 00:00:00 2001 From: Max Martens Date: Wed, 3 Jun 2026 19:06:17 +0200 Subject: [PATCH 7/7] Added JSON schema and updated examples and error specs for supplier - tweaked OAS for TP --- src/openapi/products/SE-vouchers-TP.yaml | 41 +- .../products/SE-vouchers-supplier.yaml | 749 ++++++++++++++++-- 2 files changed, 708 insertions(+), 82 deletions(-) diff --git a/src/openapi/products/SE-vouchers-TP.yaml b/src/openapi/products/SE-vouchers-TP.yaml index ebd38f3..9308e3f 100644 --- a/src/openapi/products/SE-vouchers-TP.yaml +++ b/src/openapi/products/SE-vouchers-TP.yaml @@ -28,12 +28,12 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/issuedVoucherResponse" + $ref: "#/components/schemas/salesTouchpointIssuedVoucherResponse" examples: Voucher that grants a voucher-only product for free: summary: Voucher that grants a voucher-only product for free description: |- - Voucher that grants a product (that can onlu be acquired via a voucher) for free. + Voucher that grants a product (that can only be acquired via a voucher) for free. In this case, the voucher has an amountInclTax of 0. If the requiredProduct has a non-zero sellingPrice (amountInclTax), the difference between sellingPrice and voucher amountInclTax represents the granted discount. If the requiredProduct has @@ -57,6 +57,13 @@ paths: "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_details": @@ -81,7 +88,7 @@ paths: description: |- Voucher that grants a hybrid product (that can be acquired via voucher or via ordinary order flow) 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 + 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./ @@ -142,7 +149,7 @@ paths: { "productId": 265, "productName": "Voucher 10 euro korting", - "productDescription": "Voucher die10 euro korting geeft op je gehele winkelmand.", + "productDescription": "Voucher die 10 euro korting geeft op je gehele winkelmand.", "amountInclTax": -1000, "requiredProducts": [] }, @@ -164,20 +171,20 @@ paths: "detail": "You do not have permission to access this resource.", "instance": "/issuedvouchers", } - "404": - description: Not found + "400": + description: Bad request content: application/problem+json: schema: $ref: "#/components/schemas/rfc9457" examples: - Voucher not found: - summary: Voucher not found + Invalid voucher code: + summary: Invalid voucher code value: { - "type": "https://example.com/probs/not-found", - "title": "Voucher not found", - "detail": "The voucher with code VOUCHER123 does not exist.", + "type": "https://example.com/probs/bad-request", + "title": "Invalid voucher code", + "detail": "No valid voucher found for code VOUCHER123.", "instance": "/issuedvouchers", } "500": @@ -203,7 +210,7 @@ components: scheme: bearer bearerFormat: JWT schemas: - issuedVoucherResponse: + salesTouchpointIssuedVoucherResponse: type: object required: - issuedVoucherId @@ -224,18 +231,18 @@ components: example: "HTM-A7J-128-PYT" fromInclusive: type: string - format: date-time + 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" + example: "2024-10-04T00:00:00.000+02:00" untilInclusive: type: string - format: date-time + 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" + example: "2024-11-04T00:00:00.000+01:00" voucherStatus: type: object required: @@ -258,7 +265,7 @@ components: example: "issued" product: type: object - description: The "product" referencing the voucher definition that this voucher instance is based on" + description: The "product" referencing the voucher definition that this voucher instance is based on required: - productId - productName diff --git a/src/openapi/products/SE-vouchers-supplier.yaml b/src/openapi/products/SE-vouchers-supplier.yaml index 5b1aa2b..5358343 100644 --- a/src/openapi/products/SE-vouchers-supplier.yaml +++ b/src/openapi/products/SE-vouchers-supplier.yaml @@ -21,7 +21,8 @@ paths: - 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 - - Most other attributes are also prerequisites for redeeming the voucher, but they will likely match the attributes of the product that is acquired when redeeming the voucher (voucher requires PAD attributes if the product requires PAD attributes, etc.) + + 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 @@ -59,7 +60,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/unavailable" + $ref: "#/components/schemas/supplierTouchpointVoucherDefinitionsListResponse" examples: No products / Empty list: summary: No products / Empty list @@ -69,13 +70,15 @@ paths: 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".\ - 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). + 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": 321, + "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": @@ -93,7 +96,7 @@ paths: "requiredProducts": [ { - "productId": 126, + "productId": 982, "productName": "Ooievaarspas voor AOW-ers in Den Haag", "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas.", }, @@ -106,7 +109,7 @@ paths: } ], "imageReference": "https://www.htm.nl/media/leif2leu/htm-logo-mobile.svg", - "productPageUrl": "https://www.htm.nl/nog-onbekende-product-pagina", + "termsUrl": "https://www.htm.nl/voorwaarden/vouchers/voucher-xxx-voorwaarden.pdf", "sellingPeriods": [ { @@ -145,12 +148,12 @@ paths: "internalPrice": 0.0000, "taxCode": "V09", "taxPercentage": 9.0000, - }, - ], - }, - ], - }, - ], + } + ] + } + ] + } + ] } "403": description: Forbidden @@ -243,6 +246,8 @@ paths: 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 @@ -261,13 +266,14 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/unavailable" + $ref: "#/components/schemas/supplierTouchpointIssuedVouchersListResponse" examples: - List containing one issued voucher: - summary: List containing one issued voucher + 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".\ - 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 "claims" array of the issued voucher. + 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": @@ -275,25 +281,41 @@ paths: { "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", "voucherCode": "HTM-A7J-128-PYT", - "fromInclusive": "2026-01-01T00:00:00.000+00:00", - "untilInclusive": "2030-12-31T23:59:59.000+00:00", - "voucherStatus": - { "voucherStatusId": 1, "name": "New" }, + "fromInclusive": "2024-10-04T00:00:00.000", + "untilInclusive": "2024-11-04T00:00:00.000", + "voucherStatus": { "voucherStatusId": 2, "name": "issued" }, "product": { - "productId": 321, + "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": 126, + "productId": 982, "productName": "Ooievaarspas voor AOW-ers in Den Haag", - "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas." - } - ] + "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", + }, + }, }, - "claims": + "voucherClaims": [ { "mandatoryCustomerDataItem": @@ -303,9 +325,96 @@ paths: }, "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 @@ -358,7 +467,9 @@ paths: 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). + 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: @@ -366,7 +477,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/unavailable" + $ref: "#/components/schemas/supplierTouchpointCreateIssuedVoucherRequest" examples: Issue a voucher and supply own voucher code: summary: Issue a voucher and supply own voucher code @@ -376,7 +487,7 @@ paths: "voucherCode": "HTM-A7J-128-PYT", "fromInclusive": "2026-01-01T00:00:00.000+00:00", "untilInclusive": "2030-12-31T23:59:59.000+00:00", - "productId": 321, + "productId": 263, "voucherClaims": [ { @@ -392,14 +503,7 @@ paths: { "fromInclusive": "2026-01-01T00:00:00.000+00:00", "untilInclusive": "2030-12-31T23:59:59.000+00:00", - "productId": 321, - "voucherClaims": - [ - { - "mandatoryCustomerDataItemId": 8, - "value": "1980-06-31", - } - ], + "productId": 264 } responses: "201": @@ -407,7 +511,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/unavailable" + $ref: "#/components/schemas/supplierTouchpointIssuedVoucherResponse" examples: Successfully issued a voucher: summary: Successfully issued a voucher @@ -415,24 +519,41 @@ paths: { "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", "voucherCode": "HTM-A7J-128-PYT", - "fromInclusive": "2026-01-01T00:00:00.000+00:00", - "untilInclusive": "2030-12-31T23:59:59.000+00:00", - "voucherStatus": { "voucherStatusId": 1, "name": "New" }, + "fromInclusive": "2024-10-04T00:00:00.000", + "untilInclusive": "2024-11-04T00:00:00.000", + "voucherStatus": { "voucherStatusId": 2, "name": "issued" }, "product": { - "productId": 321, + "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": 126, + "productId": 982, "productName": "Ooievaarspas voor AOW-ers in Den Haag", - "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas." - } - ] + "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", + }, + }, }, - "claims": + "voucherClaims": [ { "mandatoryCustomerDataItem": @@ -442,8 +563,43 @@ paths: }, "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 @@ -472,13 +628,13 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/unavailable" + $ref: "#/components/schemas/supplierTouchpointUpdateIssuedVoucherRequest" examples: - Mark a voucher as expired: + Mark a voucher as revoked: summary: Mark a voucher as revoked value: { - "voucherStatusId": 4, + "voucherStatusId": 4 } responses: "200": @@ -486,7 +642,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/unavailable" + $ref: "#/components/schemas/supplierTouchpointIssuedVoucherResponse" examples: Successfully updated the status of a voucher: summary: Successfully updated the status of a voucher @@ -494,23 +650,51 @@ paths: { "issuedVoucherId": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90", "voucherCode": "HTM-A7J-128-PYT", - "fromInclusive": "2026-01-01T00:00:00.000+00:00", - "untilInclusive": "2030-12-31T23:59:59.000+00:00", - "voucherStatus": { "voucherStatusId": 4, "name": "Revoked" }, + "fromInclusive": "2024-10-04T00:00:00.000", + "untilInclusive": "2024-11-04T00:00:00.000", + "voucherStatus": { "voucherStatusId": 4, "name": "revoked" }, "product": { - "productId": 321, + "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": 126, + "productId": 982, "productName": "Ooievaarspas voor AOW-ers in Den Haag", - "productDescription": "Vrij reizen bij HTM voor Haagse AOW-gerechtigden met een Ooievaarspas." - } - ] - } + "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 @@ -535,6 +719,441 @@ components: scheme: bearer bearerFormat: JWT schemas: + supplierTouchpointVoucherDefinitionsListResponse: + type: object + properties: + voucherDefinitions: + type: array + items: + $ref: "#/components/schemas/supplierTouchpointVoucherDefinitionResponse" + supplierTouchpointVoucherDefinitionResponse: + type: object + 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: