Compare commits

...

559 Commits

Author SHA1 Message Date
5133903efb OVPAY-2394 - Added example for no notificationCategories found. 2026-01-21 11:03:45 +01:00
cf0d24632f Merge pull request 'feature/OVPAY-2394' (#49) from feature/OVPAY-2394 into develop
Reviewed-on: #49
2026-01-14 12:06:39 +00:00
aa4721c651 OVPAY-2394 - Processed review remarks. 2026-01-14 13:05:32 +01:00
46bf7874d9 OVPAY-2394 - Added POST, PATCH and DELETE operations for NotificationPreferences. 2026-01-13 16:08:39 +01:00
1a14918f4a OVPAY-2394 - Added PATCH /notificationsubscriptions/{uuid}. 2026-01-13 15:45:52 +01:00
7147318900 OVPAY-2394 - Added resourceNameId to Channel. 2026-01-13 15:38:48 +01:00
e0f78d2e38 OVPAY-2394 - Updated GET /notificationsubscriptions examples. 2026-01-13 15:19:49 +01:00
ab57e27c1d OVPAY-2394 - Added OriginSubscription. 2026-01-12 15:08:32 +01:00
68c7ccc279 OVPAY-2394 - Added groupName to NotificationCategory. Added query params. 2026-01-12 13:41:20 +01:00
8946026860 Added fromInclusive and untilInclusive. 2026-01-05 13:34:12 +01:00
fb8723124a Merge pull request 'OVPAY-2378 - Updated spec for /contractpayments.' (#46) from feature/OVPAY-2378 into develop
Reviewed-on: #46
Reviewed-by: Max Martens <m.martens@htm.nl>
2025-12-29 12:31:57 +00:00
6d7c260e9e OVPAY-2378 - PaymentMethod in NL. 2025-12-29 12:32:59 +01:00
292588b7ba OVPAY-2378 - Updated spec for /contractpayments. 2025-12-29 12:01:12 +01:00
4bd216bd37 Merge pull request 'features/OVPAY2294-vouchers-in-orders' (#45) from features/OVPAY2294-vouchers-in-orders into develop
Reviewed-on: #45
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-12-16 13:57:40 +00:00
bfaa1ddcb1 fixed comments 2025-12-16 14:52:23 +01:00
55bac27561 simplified order_orderVoucherId 2025-12-15 15:36:51 +01:00
Max Martens
715a9668fc Clear up name and description of token transfer V2 endpoints 2025-12-15 14:27:48 +01:00
b4f20a9758 moved changes to TP orders to another branch and made equal to develop in this branch 2025-12-15 11:50:39 +01:00
22cb3ddd92 added query param deviceId 2025-12-15 11:43:03 +01:00
1f3e2289dc finished CRUD endpoints 2025-12-15 11:40:42 +01:00
3ff55e5888 Merge branch 'develop' of https://git.integratielaag.nl/HTM/ovpay into features/OVPAY2294-vouchers-in-orders 2025-12-15 10:44:01 +01:00
987f64a081 dubbele alias 2025-12-15 10:40:40 +01:00
00448486f3 added ovpasnumber to get token response 2025-12-15 10:39:33 +01:00
ed61633579 Merge pull request 'TapConnect V5 ticket events export schema reverse-engineered from real data' (#43) from feature/OVPAY-2345-TapConnect-Elastic into develop
Reviewed-on: #43
2025-12-15 09:01:20 +00:00
d34ba20d19 Merge branch 'develop' of https://git.integratielaag.nl/HTM/ovpay into features/OVPAY2294-vouchers-in-orders 2025-12-12 11:09:30 +01:00
3e1f23afe3 Merge pull request 'features/Edit-TP-notification' (#44) from features/Edit-TP-notification into develop
Reviewed-on: #44
2025-12-11 13:51:28 +00:00
Max Martens
6260cc5d63 Now supports handling events for TRIPS as well as ALERTS. Need to manually add xBOTs to queue using API 9853 2025-12-10 16:49:15 +01:00
d9157d04ef removed account or private from desc patch 2025-12-10 12:40:48 +01:00
f57f17e645 removed email from notification patch 2025-12-10 12:37:12 +01:00
3ae52206fc OVPAY-2370 - Status codes async jobs. 2025-12-10 12:26:09 +01:00
a52dfcab93 OVPAY-1946 - Fixed typo. 2025-12-09 16:57:10 +01:00
80b0de274e OVPAY-1946 - Updated examples. 2025-12-09 16:52:42 +01:00
38cfec81c8 removed is active from post body 2025-12-08 14:35:33 +01:00
Max Martens
3ffc525d48 Fix number typo 2025-12-08 13:30:22 +01:00
Max Martens
105a18c0ac TapConnect V5 ticket events export schema reverse-engineered from real data 2025-12-08 12:06:10 +01:00
7732ae13a6 Merge pull request 'added bulk endpoints to purchased product CRUD' (#42) from features/OVPAY2294-vouchers into develop
Reviewed-on: #42
2025-12-08 09:35:27 +00:00
4084a574c9 fixed the semantic error 2025-12-08 10:32:35 +01:00
3ebdf0090f added bulk status endpoints 2025-12-05 12:00:36 +01:00
b898288632 added bulk post to purchased product CRUD 2025-12-05 09:58:03 +01:00
dce4d5ea17 Update src/openapi/customers/SE-notifications.yaml
Fixed error in query param type.
2025-12-04 11:15:46 +00:00
e4b3ab4ccf added post voucher in SE orders 2025-12-01 16:54:10 +01:00
01aa8a9f1a Added get vouchers and voucher in response body's 2025-12-01 14:48:17 +01:00
bb917c3635 updated CRUD order swaggers for vouchers 2025-12-01 13:35:41 +01:00
e0e70af138 OVPAY-1859 - Updated id's to reflect reality. 2025-12-01 13:34:58 +01:00
ed40c1d546 Merge pull request 'Updated .NET PADP reference implementation - added ability to explicitly provide userAccessToken to requests; add V3 OTP endpoints (while also keeping V2 endpoints)' (#25) from feature/PADP-reference-POC into develop
Reviewed-on: #25
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-12-01 09:44:13 +00:00
f990a9844e OVPAY-1826 - Added YAML for one time tokens for app sales (commit from Mirjam). 2025-12-01 10:06:39 +01:00
235ec95edb Merge pull request 'fixes-customer-endpoints' (#37) from fixes-customer-endpoints into develop
Reviewed-on: #37
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-12-01 08:50:00 +00:00
76f6ed9c9f Merge pull request 'feature/OVPAY-2294' (#40) from feature/OVPAY-2294 into develop
Reviewed-on: #40
2025-11-28 14:33:25 +00:00
e6b34176c2 Merge pull request 'feature/OVPAY-2103' (#39) from feature/OVPAY-2103 into develop
Reviewed-on: #39
2025-11-28 14:33:00 +00:00
959ed1cd96 OVPAY-2294 - Introduced voucherStatusInstance. 2025-11-28 13:47:58 +01:00
d7f4cefca8 OVPAY-2103 - Updated customerTokens. 2025-11-28 12:39:19 +01:00
270217238f OVPAY-2103 - Typo OrderCustomers. 2025-11-28 11:51:05 +01:00
04be5e5fbd OVPAY-2103 - Processed review remarks. 2025-11-28 11:41:04 +01:00
cd9a2f1683 OVPAY-2103 - Typos. 2025-11-27 15:35:22 +01:00
8db879c589 OVPAY-2103 - Bugs after merge conflict, part deux. 2025-11-27 15:10:07 +01:00
8c3ad923f7 OVPAY-2103 - Bugs after merge conflict. 2025-11-27 15:05:58 +01:00
b8ad7c4ebf Merge branch 'develop' into feature/OVPAY-2103 2025-11-27 14:57:03 +01:00
de884764bd Merge pull request 'features/OVPAY1987-SE-orders-update' (#27) from features/OVPAY1987-SE-orders-update into develop
Reviewed-on: #27
2025-11-27 13:23:12 +00:00
Max Martens
403b336522 Rename HATEOAS for transfer to "transfer_token" to be in line with actual SE implementation 2025-11-27 13:22:09 +01:00
8f93fb03fd OVPAY-2103 - Updated examples existing endpoints. 2025-11-27 12:23:09 +01:00
6f95cee75e OVPAY-2103 - Added endpoints for TapConnectTicket. 2025-11-27 11:35:13 +01:00
b0360c22be OVPAY-2103 - Added endpoints for IssuedVoucher. 2025-11-27 11:01:09 +01:00
bfa400820f OVPAY-2103 - Added batch endpoints for bulk patch processing failures. 2025-11-27 09:42:35 +01:00
62ab18b8e8 OVPAY-2103 - Added emty attributes under customerTokens. 2025-11-26 16:11:16 +01:00
361d194bc4 OVPAY-1946 - Updated bulk responsestatus endpoints. 2025-11-26 15:23:18 +01:00
207c6961a8 OVPAY-1946 - Updated bulk endpoints. 2025-11-26 15:17:58 +01:00
70842ca9dc OVPAY-2103 - Created two versions of get concept order for known and anon token. 2025-11-21 17:09:33 +01:00
b51ce9cee1 OVPAY-2103 - Updated relevant examples of concept orders. 2025-11-21 17:02:08 +01:00
0b91eae4fa OVPAY-2103 - Updated examples for POST order. 2025-11-21 15:00:00 +01:00
482911d717 OVPAY-2103 - Added example for get single order. 2025-11-21 14:54:05 +01:00
a4f33c5439 OVPAY-2103 - Added ovPayToken info to get orders. 2025-11-21 14:36:29 +01:00
3230465cbb OVPAY-2103 - Added epurse and pad attributes to get orders. 2025-11-19 16:53:11 +01:00
6e3aa3a04b OVPAY-2103 - Removed unused endpoints. 2025-11-19 15:52:46 +01:00
b1bbe6b0cb OVPAY-2103 - Removed v1 examples from OAS. 2025-11-19 15:33:36 +01:00
e47464f4a6 removed customerSTatusInstanceId 2025-11-18 13:49:23 +01:00
57281afdc8 OVPAY-94 - Typo. 2025-11-18 10:07:25 +01:00
6de1d6f22b semantic error 2025-11-17 15:19:45 +01:00
61332e38c6 small fixes preference and status Id's 2025-11-17 15:16:26 +01:00
83eee59e58 Merge pull request 'Make amountExclTax, taxCode, taxPercentage nullable schemas (+ example value always null for amountExclTax)' (#36) from feature/OVPAY-2033-optionalTax into develop
Reviewed-on: #36
2025-11-13 14:36:18 +00:00
Max Martens
de998b9add Make amountExclTax, taxCode, taxPercentage nullable schemas (+ example value always null for amountExclTax) 2025-11-13 15:35:16 +01:00
527ead5258 Update src/openapi/customers/customers-crud-v2.yaml 2025-11-11 12:19:40 +00:00
14d3891618 Merge pull request 'OVPAY-94 - Updated notification cruds after comments DHIL.' (#35) from feature/OVPAY-94 into develop
Reviewed-on: #35
2025-11-06 10:55:13 +00:00
3714fe32b0 OVPAY-94 - Remove HATEOAS. 2025-11-06 11:44:26 +01:00
2ea4af5211 OVPAY-94 - Typo. 2025-11-06 11:20:46 +01:00
6015347db3 OVPAY-94 - Updated notification cruds after comments DHIL. 2025-11-06 10:57:24 +01:00
47204b3b75 Merge pull request 'features/TP-notifications' (#34) from features/TP-notifications into develop
Reviewed-on: #34
2025-11-06 09:18:19 +00:00
63fa5a6e98 fixed the mengelmoes category 2025-11-06 09:57:11 +01:00
b5131629a9 review comments 2025-11-05 15:28:30 +01:00
3d42458d12 switched request body and response 2025-11-03 14:46:08 +01:00
4202bb03f1 Updated maileon API's 2025-11-03 14:37:19 +01:00
d48669a25c updated 2025-11-03 14:26:21 +01:00
3cbcbeaf6d Merge pull request 'feature/OVPAY-94' (#33) from feature/OVPAY-94 into develop
Reviewed-on: #33
2025-11-03 08:35:53 +00:00
81b3a0c96d OVPAY-94 - Updated schemas. 2025-10-29 17:51:31 +01:00
f63fbe1c9a OVPAY-94 - Updated to Maileon MVP. 2025-10-29 17:49:37 +01:00
b2404f9ff9 things 2025-10-29 15:12:12 +01:00
b6a52e244e endpoints 2025-10-29 15:10:07 +01:00
7383116ecd endpoints 2025-10-29 15:08:32 +01:00
f6f77421e2 added SE api's voor maileon 2025-10-29 15:05:26 +01:00
c77c05895d updated customer crud endpoints with is emailverified 2025-10-29 13:50:19 +01:00
11390d2275 updated tags 2025-10-29 13:43:19 +01:00
dad2304155 removed TODO's 2025-10-29 13:36:59 +01:00
Max Martens
d2ffe35513 Fixed saldo product example (now 1 cent instead of 100 cent) 2025-10-28 15:23:30 +01:00
e73e3bd779 updated 2025-10-27 16:34:21 +01:00
b518f4fbd1 updated get categories with expand param 2025-10-22 14:46:38 +02:00
f2d8532f7f added nesting to response subscriptions 2025-10-22 12:00:53 +02:00
d7d9c23a5a first version of swagger, WIP 2025-10-20 16:36:46 +02:00
Max Martens
c9bd3ed72d Smallest fix ever 2025-10-16 15:41:03 +02:00
Max Martens
1bbbd9c9a2 Add isArchived query param to ABTProducts CRUD 2025-10-16 15:27:58 +02:00
4d2fb6ca3c OVPAY-973 - Added query params. 2025-10-16 12:45:41 +02:00
b2959be276 OVPAY-973 - Temporarily commented deviceId. 2025-10-15 16:38:05 +02:00
62cd075f2e OVPAY-973 - Model rework. 2025-10-15 16:35:48 +02:00
6f78ce4020 Merge pull request 'feature/OVPAY-2186' (#31) from feature/OVPAY-2186 into develop
Reviewed-on: #31
2025-10-15 10:42:40 +00:00
546d655054 Merge branch 'develop' into feature/OVPAY-2186 2025-10-15 10:42:30 +00:00
a4b0578420 Merge pull request 'OVPAY-1946 - Added bulk reject/return endpoints.' (#32) from feature/OVPAY-1946 into develop
Reviewed-on: #32
2025-10-13 10:52:20 +00:00
c5a3b36885 OVPAY-1946 - Added bulk reject/return endpoints. 2025-10-06 10:55:52 +02:00
b41b00fa04 Merge branch 'feature/OVPAY-2018' into develop 2025-10-03 15:12:09 +02:00
e13122a309 Merge branch 'develop' into feature/OVPAY-2018 2025-10-03 15:02:12 +02:00
2b24c18417 Merge pull request 'feature/OVPAY-973' (#30) from feature/OVPAY-973 into develop
Reviewed-on: #30
2025-10-03 12:10:34 +00:00
d2176dfdc3 OVPAY-2018 - Processed review remarks. 2025-10-03 14:02:21 +02:00
328aea468b OVPAY-973 - Processed review remarks. 2025-10-03 13:13:05 +02:00
ae7534c0b7 ovchipcard fix 2025-10-02 11:09:17 +02:00
79faa8ab3d OVPAY-2186 - Added contractStatusId = 8. 2025-10-02 09:58:24 +02:00
5bd56be578 OVPAY-2186 - Added proper schema for other endpoints. Added DELETE /contractversions. 2025-10-02 09:42:59 +02:00
7a2ecec133 OVPAY-2186 - Added proper schema for POST contracts. 2025-10-01 16:11:00 +02:00
b666f333cc OVPAY-2186 - Endpoint naming fix. 2025-10-01 15:58:20 +02:00
581d9a0658 OVPAY-2186 - Added contractversion to /customers/{customerProfileId}/contracts. 2025-10-01 15:46:28 +02:00
90559cd633 OVPAY-2186 - Re-added product (as joined field) on contract-level. 2025-10-01 15:37:42 +02:00
87e98ed975 casing 2025-10-01 15:26:46 +02:00
66f65a6b12 merge conflict 2025-10-01 15:17:35 +02:00
cba1f2b491 casing customer crud 2025-10-01 15:14:35 +02:00
9950cadcf3 OVPAY-2186 - Updated SE examples. 2025-10-01 14:23:44 +02:00
966602d8b0 OVPAY-2186 - Updated schema. 2025-10-01 14:15:57 +02:00
1c8183632a OVPAY-2186 - Updated examples. 2025-10-01 14:01:43 +02:00
fea8e01e47 Bugfix. 2025-10-01 11:34:52 +02:00
Max Martens
d1b83d19b5 Refactor layerInfo to communicate what differentiates underlying variants, instead of being defined on every variant itself 2025-09-30 18:04:04 +02:00
Max Martens
67e459d1b0 Support for layerInfo, fix some null attribute namings 2025-09-29 08:16:09 +02:00
b99e6b83c7 Merge pull request 'Add productcategory for saldo and product examples for saldo and change IBAN mandate' (#28) from feature/OVPAY-2029-saldo into develop
Reviewed-on: #28
2025-09-26 16:42:54 +00:00
Max Martens
b7801e6871 Merge branch 'develop' into feature/OVPAY-2029-saldo 2025-09-26 18:42:16 +02:00
Max Martens
5aabd3e529 Add fikoArticleNumber everywhere; set amountExlTax to null everywhere to prepare for upcoming deprecation 2025-09-26 18:41:23 +02:00
1413cbd01d OVPAY-1110 - Added endpoint to undo pending contract cancellation. 2025-09-15 12:03:11 +02:00
17d7b77541 TransactionId, transactionLineId and articleNumber are strings. 2025-09-15 10:55:54 +02:00
bdfff9377b fixed merge conflicts 2025-09-13 21:34:06 +02:00
a7c1908d00 DateOfBirth and Birthdate are always formatted YYYY-MM-DD. 2025-09-12 12:53:42 +02:00
f4bbb0d2e2 OVPAY-973 - Added HATEOAS, pagination and reference API's. 2025-09-10 17:37:29 +02:00
e4472a2ae7 OVPAY-973 - Added CRUD operations for NotificationSubscription. 2025-09-10 11:16:42 +02:00
3c7a9d3cb9 OVPAY-2018 - Added touch point endpoints. 2025-09-09 14:35:41 +02:00
a2e81d0f43 OVPAY-2018 - Added devices patch response. 2025-09-09 11:16:24 +02:00
11add823da OVPAY-2018 - Added schemas. 2025-09-08 12:02:15 +02:00
Max Martens
d5cbf06ec4 Add examples for saldo and change IBAN mandate (only in CRUD for now, not yet in SE/TP) 2025-09-05 18:23:03 +02:00
Max Martens
361813a734 Add productCategory 8 (saldo), with isTravelProduct=true (as it can only exist on an OV-pas) 2025-09-05 18:21:57 +02:00
f5bf3d62de OVPAY-2018 - Added endpoints and examples for Customer Devices. 2025-09-05 16:17:31 +02:00
840b62f493 Merge pull request 'OVPAY-2002 - Added YAML for Sendgrid OAS3.' (#22) from feature/OVPAY-2002 into develop
Reviewed-on: #22
2025-09-05 12:40:33 +00:00
71575926d6 layerinfo url lowercase 2025-09-04 12:18:35 +02:00
2c9cd23b2f Merge pull request 'updated the patches' (#26) from feature/OVPAY2095-customersv2patch into develop
Reviewed-on: #26
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-09-01 12:29:24 +00:00
6337cbc578 phonenumber en coutrycode stringified 2025-09-01 13:47:11 +02:00
617099c1a8 naming examples 2025-09-01 13:19:10 +02:00
8730cfbe99 updated the patches 2025-09-01 12:24:11 +02:00
24c9c8ab6e Merge pull request 'feature/OVPAY-2007-Products-LayerInfo' (#24) from feature/OVPAY-2007-Products-LayerInfo into develop
Reviewed-on: #24
2025-08-28 09:26:23 +00:00
Max Martens
0515529551 fixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 2025-08-28 11:24:22 +02:00
Max Martens
d9d82eae66 fixxxxxxxxxxxxx 2025-08-28 11:22:04 +02:00
Max Martens
1eec7eab28 Add ability to explicitly provide userAccessToken to requests; add V3 OTP endpoints (while also keeping V2 endpoints) 2025-08-28 10:44:22 +02:00
Max Martens
227fa07da0 Added CRUD POST/PUT examples with layerInfo 2025-08-28 10:36:22 +02:00
9fe5913be3 Merge pull request 'OVPAY-2032 - Added profile instances to the get token call.' (#23) from feature/OVPAY-2032 into develop
Reviewed-on: #23
2025-08-25 13:33:55 +00:00
4d9e6a831f Review comments verwerkt 2025-08-25 15:32:14 +02:00
270ea246df changed GET customers to always return a list 2025-08-19 15:23:55 +02:00
908afa2bc0 added existing post patch customer to SE swagger 2025-08-19 12:12:58 +02:00
Max Martens
3ecf55b6ec SE and TP OAI now also fixed, including multi-layer example for LayerInfo 2025-08-17 23:30:57 +02:00
Max Martens
d4c5165b39 Fixed 2025-08-17 22:25:49 +02:00
Max Martens
7de54cbd86 WIP, still need to fix some very legacy incorrect confusing stuff in this OAI-spec (thanks Greg for pointing that out!) 2025-08-17 19:53:29 +02:00
Max Martens
ad58b53440 Ultra major refactor of ABTProductReference Swagger; added new LayerInfo entity 2025-08-14 14:27:46 +02:00
d8a6a59c7d OVPAY-2032 - Added product instances to the compare call. 2025-08-14 11:59:13 +02:00
57607d8ad7 OVPAY-2032 - Added profile instances to the compare call. 2025-08-14 11:53:19 +02:00
adcbc4e61c OVPAY-2032 - Added profile instances to the get token call. 2025-08-14 11:41:25 +02:00
ba8a31c94f derp 2025-08-07 17:34:45 +02:00
5e79d30c7c derp 2025-08-07 17:32:44 +02:00
343b74c038 updated specs 2025-08-07 16:20:15 +02:00
a87058641d OVPAY-2002 - Removed invisible Unicode characters 2025-08-06 15:28:59 +02:00
5f0f8500d4 OVPAY-676 - Minor improvements on GET /contractpayments. 2025-08-06 15:19:40 +02:00
ea8b7f9986 OVPAY-2002 - Added YAML for Sendgrid OAS3. 2025-08-06 13:02:29 +02:00
84b8b37a98 Merge pull request 'updated CRUD swagger' (#21) from features/OVPAY1986-aanpassingenOrderCRUD into develop
Reviewed-on: #21
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-08-01 12:47:45 +00:00
43d4ecb477 PATCH and DELETE under orderLines 2025-08-01 12:00:39 +02:00
660fc2e151 fix local and remote 2025-07-31 14:42:27 +02:00
0bdd2233ac stuff 2025-07-30 17:46:00 +02:00
7aa4c6de87 orderLineTerms call 2025-07-30 17:43:52 +02:00
e9ecc39c25 stuff 2025-07-30 17:29:33 +02:00
69e2f40003 stuff 2025-07-30 17:28:16 +02:00
04fda84f01 indentation 2025-07-30 17:26:15 +02:00
e150018a78 updated CRUD swagger 2025-07-30 17:21:53 +02:00
b8dd854805 Merge pull request 'feautures/OVPAY1868-endpoint-token-vervangen' (#19) from feautures/OVPAY1868-endpoint-token-vervangen into develop
Reviewed-on: #19
Reviewed-by: Max Martens <m.martens@htm.nl>
2025-07-29 15:38:56 +00:00
2bdc65cba3 fixed urls 2025-07-28 16:23:16 +02:00
bc50dc58ea padp-poc-openapi.yaml 2025-07-28 10:32:15 +02:00
a775a3207b ovpasnumber as string 2025-07-25 09:53:45 +02:00
a7afa7ff58 added all the urls on ACC 2025-07-24 16:36:46 +02:00
db65105b7c Merge pull request 'added remarks from Hari' (#20) from features/OVPAY1293-notes-during-dev into develop
Reviewed-on: #20
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-07-24 14:14:30 +00:00
3d4b07a400 - ov 2025-07-24 16:08:38 +02:00
8df1aa8e6b fixed SIGNED 2025-07-24 15:58:46 +02:00
f21d30644f added remarks from Hari 2025-07-24 15:45:19 +02:00
e4ab84592f updated base url SE customers endpoints 2025-07-24 10:47:29 +02:00
f9523adf83 Merge pull request 'OVPAY-1893 - Added ContractInvoice.invoiceDate.' (#17) from feature/OVPAY-1893 into develop
Reviewed-on: #17
2025-07-10 13:25:42 +00:00
69e9392410 OVPAY-1893 - Added invoiceDate query param. 2025-07-10 15:09:00 +02:00
e668b95b8b OVPAY-1893 - Added ContractInvoice.invoiceDate. 2025-07-10 14:55:37 +02:00
780594022a Merge pull request 'Fix example naming' (#16) from feature/OVPAY-1293-fix into develop
Reviewed-on: #16
2025-07-08 11:06:25 +00:00
Max Martens
319392ca51 Remove incomplete security block that casues errors in Swagger UI 2025-07-08 11:34:32 +02:00
Max Martens
db463f0ada Fix example naming 2025-07-08 11:26:19 +02:00
458450ada9 Merge pull request 'OVPAY-676 - Added GET /contractpayments.' (#15) from feature/OVPAY-676 into develop
Reviewed-on: #15
2025-06-27 10:54:28 +00:00
939ce9fd80 OVPAY-676 - Added GET /contractpayments. 2025-06-26 11:03:30 +02:00
065d513594 Merge pull request 'Update for datamodel v2.5, Fix version in SE/TP to reflect reality' (#14) from feature/OVPAY-1862-ABTProducts into develop
Reviewed-on: #14
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-06-19 21:26:51 +00:00
Max Martens
8e5522524c Add two new attributes isValid and isArchived (only in CRUD, SE/TP will never get those attributes in response); update to correct Regio Vrij gboPackageTemplateIds 2025-06-18 20:59:30 +02:00
Max Martens
87f19f756b Update for datamodel v2.5, Fix version in SE/TP to reflect reality 2025-06-17 12:12:48 +02:00
f1728ecebf Merge branch 'feature/OVPAY-982' into develop 2025-06-16 11:35:37 +02:00
58df9ee097 Merge pull request 'feature/OVPAY-1755' (#12) from feature/OVPAY-1755 into develop
Reviewed-on: #12
2025-06-11 13:10:34 +00:00
0f0f192212 OVPAY-1643 - Updated 'Transfer in progress' example response. 2025-06-04 15:30:04 +02:00
cfebf41dc3 OVPAY-1643 - Small improvements. 2025-06-04 11:27:01 +02:00
a5cc061677 OVPAY-1643 - Token replace v2 is now async. 2025-06-04 11:16:10 +02:00
66dd59ffe0 Merge pull request 'delete token and 1 PAD object per token' (#11) from feature/OVPAY1820-CRUD-OrdersV2 into develop
Reviewed-on: #11
2025-05-26 12:24:01 +00:00
b39637a4ec typos 2025-05-26 14:23:35 +02:00
43bca1a87d error message post PAD 2025-05-26 14:16:15 +02:00
fc8596f0f3 delete token and 1 PAD object per token 2025-05-26 12:15:44 +02:00
a09058d151 merged develop 2025-05-21 13:04:51 +02:00
17d10c158c OVPAY-1784 - Fixed timestamps. 2025-05-21 10:28:05 +02:00
3d68dfb7eb Merge pull request 'updated customer v1' (#42) from feature/1700-part-2-update-V1 into develop
Reviewed-on: #42
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-05-19 11:30:24 +00:00
a6491041cb dinges 2025-05-19 13:25:06 +02:00
9c9c96453f shenanigens updated and created financials 2025-05-19 13:21:29 +02:00
920246f499 removed is preferred example 2025-05-19 12:42:35 +02:00
ec6edd3636 updated customer v1 2025-05-19 12:28:15 +02:00
18c507195d Merge pull request 'updated customer CRUD' (#41) from feature/OVPAY-1700-customer-address into develop
Reviewed-on: #41
2025-05-19 07:18:29 +00:00
d8d2e31e52 fix 2025-05-19 09:17:25 +02:00
e5867aa605 updated customer CRUD 2025-05-16 13:54:04 +02:00
6b0fe72901 OVPAY-1564 - ENdpoints /transfer and /replace now only support XTAT for target token. 2025-05-15 10:52:51 +02:00
4702ddae4a OVPAY-1564 - Adjusted POST /payments request and response body. 2025-05-14 12:07:49 +02:00
bec2e990fb OVPAY-1742 - Stasjo. 2025-05-13 17:06:53 +02:00
6dffa72825 OVPAY-1742 - Added more examples for development. 2025-05-13 10:03:41 +02:00
2df187ac59 OVPAY-1742 - xTAT casing. 2025-05-13 09:18:52 +02:00
343d49a9c8 OVPAY-1742 - Removed incorrect 404 response example from /transfer. 2025-05-12 18:35:17 +02:00
8da955c5cf OVPAY-1742 - Improved examples for /transfer. 2025-05-12 18:34:07 +02:00
a58971d1c9 OVPAY-1742 - Added X-HTM headers to /compare and /transfer. 2025-05-12 17:15:37 +02:00
a34fd67268 OVPAY-1742 - Added examples for development. 2025-05-12 17:05:53 +02:00
ea5a3aee69 OVPAY-1742 - Split /transfer into old and new endpoint. 2025-05-12 17:01:00 +02:00
db844e2c39 OVPAY-1784 - CRUD for NFC card reader. 2025-05-12 13:54:19 +02:00
937962401b OVPAY-1438 - Added cardreader YAML. 2025-05-12 12:19:22 +02:00
7c76658884 OVPAY-1742 - Fixed typo. 2025-05-12 11:08:37 +02:00
7361d5fca3 Merge pull request 'feature/OVPAY-1742' (#40) from feature/OVPAY-1742 into develop
Reviewed-on: #40
2025-05-12 08:00:44 +00:00
e58ce0feca Merge branch 'develop' into feature/OVPAY-1742 2025-05-12 08:00:12 +00:00
d280bfbad5 OVPAY-1742 - Fixed typo. 2025-05-12 09:59:02 +02:00
Max Martens
b7ff9055e5 Finish /transfer spec, add schema for request body for /compare and /transfer 2025-05-09 17:19:18 +02:00
Max Martens
aba341d14b Add two more examples (non transferable products and unsupported token type combination) 2025-05-09 17:01:03 +02:00
Max Martens
35edfa4c4f WIP 2 2025-05-09 16:56:33 +02:00
Max Martens
8cced0cbd0 WIP 2025-05-09 16:52:44 +02:00
Max Martens
345a12fa90 Add 1211 to PADP Swagger; token compare/replace is added to SE-customers in OVPAY-1742 feature branch and PR 2025-05-08 19:04:38 +02:00
Max Martens
3819ee006f Update binary 2025-05-08 13:29:54 +02:00
Max Martens
9fd0a14e91 Fix PUTGenerator 2025-05-07 11:31:04 +02:00
faa4ea6877 always validation keys in response 2025-05-06 16:12:32 +02:00
797a7d488f ensured consistent versioning in spec 2025-05-06 16:05:19 +02:00
499442b3d9 OVPAY-1742 - Added examples for transferring existing tokens without PAD. 2025-05-06 15:02:22 +02:00
c692718fbb OVPAY-1742 - Added PAD OTP and PAD email address to transfer request body. 2025-05-06 14:28:40 +02:00
d8f9706d76 OVPAY-1742 - Added replace by XTAT example. 2025-05-02 15:08:06 +02:00
946ba3f898 OVPAY-1742 - Added examples for unhappy transfer flow. 2025-05-02 14:57:11 +02:00
079c16763e OVPAY-1742 - Added examples for unhappy flow. 2025-04-30 17:04:34 +02:00
59db7d7323 OVPAY-1742 - Added endpoint for transfer. 2025-04-30 16:02:20 +02:00
14228a5d66 OVPAY-1742 - Updated description for /compare endpoint. 2025-04-30 15:42:00 +02:00
6c3a15134e OVPAY-1742 - Added /compare endpoint. 2025-04-30 15:39:36 +02:00
8e5dcacff5 Merge pull request 'TP PAD Swagger with only final endpoints incouded' (#39) from feature/TP-PAD into develop
Reviewed-on: #39
2025-04-30 11:02:13 +00:00
Max Martens
38b7e2240c Niceness 2025-04-30 12:38:01 +02:00
Max Martens
4c8032a4e0 TP PAD Swagger with only final endpoints incouded 2025-04-30 12:32:31 +02:00
6e0b613463 OVPAY-1755 - Updated AccoutingPeriodMetadata. 2025-04-28 14:51:52 +02:00
248208ec7b OVPAY-1755 - Updated SourceMetadata. 2025-04-28 14:49:22 +02:00
a1175b57d8 OVPAY-1755 - Updated TaxMetadata. 2025-04-28 14:34:43 +02:00
7097b49097 OVPAY-1755 - Added delete of concessionmetada. 2025-04-28 14:14:52 +02:00
33fa5e408c OVPAY-1755 - Updated the examples of ConcessionMetdata. 2025-04-28 14:09:24 +02:00
ea6d8d1864 OVPAY-1755 - Updated BookingProcesses. 2025-04-28 13:58:54 +02:00
1a853a11ef OVPAY-1755 - Updated BookingLineMetadata. 2025-04-28 13:52:36 +02:00
a6f85b32fc OVPAY-1755 - Updated BookingMetadata. 2025-04-28 11:35:13 +02:00
323f1c195c review commentaar 2025-04-28 10:38:30 +02:00
52d4d21871 correct verif code token 2025-04-25 09:15:46 +02:00
17feb74889 prioritering in API's 2025-04-24 17:46:48 +02:00
d0b999236f token options 2025-04-24 17:06:18 +02:00
4b70e09458 description 2025-04-24 13:37:41 +02:00
dd5874c893 orderline patch for a later release 2025-04-24 13:33:37 +02:00
f2688e1f73 added personalaccountdata endpoints to SE orders 2025-04-22 11:58:27 +02:00
bacdab0575 fix 2025-04-18 13:46:24 +02:00
a2d42774cb GET order with validation, extend orderLine patch, post and delete customerToken 2025-04-18 13:42:22 +02:00
038427ffc1 OVPAY-12 74Added FIKO example XML. 2025-04-18 11:08:22 +02:00
Max Martens
fef35cc8f6 Fix timezone from "+0:00" to "+00:00" 2025-04-17 12:52:14 +02:00
Max Martens
67bb707553 Fixed gboAgeProfile naming mistakes 2025-04-17 11:15:06 +02:00
Max Martens
ecd695b198 Add new fields to tool for generating request bodies for new products model 2025-04-15 19:06:57 +02:00
8b8f114cfd camelcase touchPointId 2025-04-15 15:57:56 +02:00
e1bc8db6ba Merge pull request 'removed addressId linked to customerprofile and lowercase birthdate' (#35) from feature/OVPAY1700-orders into develop
Reviewed-on: #35
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-04-15 10:56:02 +00:00
8c94204251 removed addressId linked to customerprofile and lowercase birthdate 2025-04-15 11:40:50 +02:00
b905164abc Merge pull request 'OVPAY-1697 - Updated to Order model v2.1.' (#33) from feature/OVPAY-1697 into develop
Reviewed-on: #33
2025-04-14 11:55:08 +00:00
1b2d562da7 Merge branch 'develop' into feature/OVPAY-1697 2025-04-14 11:54:44 +00:00
17812e423e Merge pull request 'added xTat to get tokens' (#34) from features/OVPAY1643-SE-Tokens into develop
Reviewed-on: #34
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-04-13 20:29:16 +00:00
4b666b082c added xTat to get tokens 2025-04-11 15:48:47 +02:00
3aadfd65a3 OVPAY-1697 - Updated to Order model v2.1. 2025-04-11 14:58:56 +02:00
34ba110b1a Merge pull request 'OVPAY-1634 endpoint for touchpoints to get GBO age profile that is valid for the given input' (#27) from feature/OVPAY-1634-gboAgeProfile-endpoint into develop
Reviewed-on: #27
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-04-07 10:18:22 +00:00
f6a7838ae4 Merge pull request 'Update ABTProducts' (#28) from feature/OVPAY-1623-ABTProducts into develop
Reviewed-on: #28
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-04-07 10:17:43 +00:00
Max Martens
024af73bce lowercase p 2025-04-07 12:17:08 +02:00
Max Martens
5bb8694b25 Fixed number and taxId type in examples 2025-04-07 12:07:12 +02:00
Max Martens
74347acf9d Fix productOwners PUT/DELETE 2025-04-03 12:54:30 +02:00
Max Martens
6a74d553ff Fix POST examples, add mandatoryCustomerDataItems shippingAddress and billingAddress 2025-04-03 12:47:25 +02:00
46f5103c73 Merge pull request 'Swag (er for APIM endpoint 1211)' (#32) from feature/OVPAY-1588 into develop
Reviewed-on: #32
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-04-01 15:22:01 +00:00
Max Martens
f5ba36449e Add partially filled PAD example 2025-04-01 17:20:15 +02:00
Max Martens
3c711c091a Add valid examples for 400/404/500 2025-04-01 17:13:08 +02:00
17cc462a8e Merge branch 'develop' into feature/OVPAY-1634-gboAgeProfile-endpoint 2025-04-01 11:00:28 +00:00
Max Martens
204d347456 Swag 2025-04-01 12:53:14 +02:00
Max Martens
c0f83f4b40 Add gitignore for .NET 2025-04-01 12:46:03 +02:00
7debf77c5d OVPAY-1564 - Added "validContents" to order. 2025-03-31 13:58:47 +02:00
ef9ea011d3 OVPAY-1564 - "terms" is now "orderLineTerms". 2025-03-31 13:18:35 +02:00
9f86b15ca5 Merge pull request 'feature/OVPAY-1645-token-refactor' (#31) from feature/OVPAY-1645-token-refactor into develop
Reviewed-on: #31
2025-03-31 11:16:50 +00:00
c9fa532d44 Merge pull request 'features/OVPAY-1675-Order-crud' (#30) from features/OVPAY-1675-Order-crud into develop
Reviewed-on: #30
2025-03-31 11:16:35 +00:00
6a4a571da7 ovpasnumber 2025-03-31 13:15:59 +02:00
acaa9861aa final quote 2025-03-31 13:08:38 +02:00
5231675d7f OVPAY-1564 - Bugfix on MandateInput (two occurences). 2025-03-31 13:01:43 +02:00
24c06c52b1 Merge branch 'develop' into feature/OVPAY-1623-ABTProducts 2025-03-31 09:54:48 +00:00
Max Martens
62c1f3a8e6 Finish SE and TP Swaggers 2025-03-31 11:48:36 +02:00
be6676a00f 1 px base64 2025-03-31 11:45:21 +02:00
af52cf93cd fixes 2025-03-31 11:31:39 +02:00
afb46f8f84 Added examples needed for stub. 2025-03-28 19:10:02 +01:00
68464bbb78 fixed typos 2025-03-28 16:54:11 +01:00
1a8497ae70 updated touchpoint id in response to nested object 2025-03-28 16:35:49 +01:00
b33c8308b7 added base64 for photo and added more fields in de patch for PAD to show full range 2025-03-28 16:30:20 +01:00
88ec45425d removed schema from hateoas link example 2025-03-28 15:49:32 +01:00
f3474dc10f updated crud customers with token status update 2025-03-28 12:33:54 +01:00
c0df05301b added tokenStatus updates 2025-03-28 12:27:31 +01:00
73b982d35f Merge pull request 'feature/OVPAY-1564' (#29) from feature/OVPAY-1564 into develop
Reviewed-on: #29
2025-03-28 11:25:27 +00:00
bd08005a46 OVPAY-1564 - Processed review remarks. 2025-03-28 12:21:47 +01:00
976e24775e cleaned op hateoas linksv 2025-03-28 10:42:44 +01:00
f6766f9225 all token endpoints added in swagger 2025-03-28 10:32:24 +01:00
07f69e089b example for pesonalization hateoas link 2025-03-27 17:01:48 +01:00
5138662556 first version 2025-03-27 16:14:55 +01:00
b9cd76e484 stuff 2025-03-26 15:39:30 +01:00
0c38563121 fout in body call 2025-03-26 15:35:46 +01:00
d8f9845ab4 fikoArticleNumber 2025-03-26 15:31:31 +01:00
b6e9a1f2f4 fixed uppercase 2025-03-26 12:57:16 +01:00
62e2dbc78d added pad changes to order crud 2025-03-26 12:06:56 +01:00
2726ddb332 updated tax fields in orders 2025-03-26 11:45:55 +01:00
6518d83c1b OVPAY-1564 - Improvements in validation objects, part 5. 2025-03-25 16:44:49 +01:00
985fdce7bb OVPAY-1564 - Improvements in validation objects, part 4. 2025-03-25 16:39:07 +01:00
Max Martens
acf2cf57e9 SE products WIP 2025-03-25 16:16:14 +01:00
8ac15a7b09 OVPAY-1564 - Improvements in validation objects, part 3. 2025-03-25 16:02:05 +01:00
ceb0137aca OVPAY-1564 - Improvements in validation objects, part 2. 2025-03-24 15:35:30 +01:00
Max Martens
6e01f688d8 Remove old v2.2 CRUD YAML, add ProducReference CRUD YAML (Based on WSO2 export) with added GboAGeProfiles 2025-03-24 13:59:41 +01:00
b7d8eff312 Add ovPasNumber and verificationCode, make birthDate optional, change type of amount to integer 2025-03-24 11:28:03 +00:00
Max Martens
5de1c15062 Update ABTProducts CRUD 2025-03-24 11:19:43 +01:00
5ec911727b Fix typo in filename 2025-03-24 08:59:40 +00:00
20a50aa501 Rename minAge and maxAge to ageFromInclusive and ageUntilInclusive 2025-03-24 08:59:04 +00:00
Max Martens
3e4760f6c4 Add 404 error when no PAD present for OVpay token 2025-03-21 17:57:18 +01:00
Max Martens
665ca2aae1 Add OpenAPI spec for retrieving GboAgeProfile 2025-03-21 17:40:55 +01:00
Max Martens
8831de0ba9 Add gitignore for local padp poc files 2025-03-21 17:39:35 +01:00
53b36f29a8 Merge pull request 'OVPAY-1637 - Add "ovPayTokenId" to GET response bodies.' (#21) from feature/OVPAY-1637 into develop
Reviewed-on: #21
Reviewed-by: ovpay <j.beek@htm.nl>
2025-03-21 14:10:01 +00:00
8ce82875ed Merge branch 'develop' into feature/OVPAY-1637 2025-03-21 14:09:45 +00:00
ffb320eaf0 OVPAY-1637 - Added "ovPayTokenId" to response body (AGAIN!!). 2025-03-21 10:44:58 +01:00
a6005c6f2f OVPAY-1564 - Improvements in validation objects, part 1. 2025-03-20 17:12:01 +01:00
067f510d50 OVPAY-1518 - taxPercentageAmount should be number. 2025-03-18 17:25:58 +01:00
57e37d5736 OVPAY-1518 - Updated examples to Odata. 2025-03-18 16:48:09 +01:00
f43626dcc7 OVPAY-1518 - Added security schemas. 2025-03-18 15:15:07 +01:00
5724c0c3cf OVPAY-1518 - And I "quote" ... 2025-03-18 15:09:22 +01:00
93a0099943 OVPAY-1518 - Updated schemas of Odata GET requests. 2025-03-18 15:07:34 +01:00
25cbf6dc10 OVPAY-1518 - Updated endpoints so they correspond to WSO2. 2025-03-18 13:51:31 +01:00
6b2d1788f4 Merge pull request 'Simple Java tool to generate ABTProducts PUT request body from GET response body' (#25) from feature/Java-products-PUT-generator into develop
Reviewed-on: #25
Reviewed-by: Bas Boterman <b.boterman@htm.nl>
2025-03-17 15:19:26 +00:00
79dbbe14ff OVPAY-1564 - Added token information to POST orders. 2025-03-17 13:37:45 +01:00
1d2d767f31 Merge pull request 'feature/OVPAY-1293' (#10) from feature/OVPAY-1293 into develop
Reviewed-on: #10
2025-03-17 09:58:53 +00:00
efb62a6abd OVPAY-1293 - Processed review remarks myself. 2025-03-17 10:57:15 +01:00
Max Martens
d1a9cb4cd0 Tweak logging and readme 2025-03-17 10:00:46 +01:00
Max Martens
35f9cccc05 Add project files, ready to use standalone jar, readme, example input+output 2025-03-17 08:52:38 +01:00
383ea04bcc OVPAY-1564 - Changes in POST /orders. 2025-03-14 18:01:05 +01:00
387bf909ad OVPAY-1564 - Typo in examples. 2025-03-14 09:30:01 +01:00
d9bfbe4c3d OVPAY-1637 - "ovPayTokenId" is a query param, not a path param. 2025-03-12 16:39:51 +01:00
bd67e51713 OVPAY-1637 - Moved "ovPayTokenId" to HATEOAS links. 2025-03-12 16:29:46 +01:00
df4500b643 OVPAY-1637 - Add "ovPayTokenId" to GET response bodies. 2025-03-12 11:41:29 +01:00
ae5ab74672 Merge pull request 'OVPAY-1352 - Added InvoiceAccountingStatus.' (#12) from feature/OVPAY-1352 into develop
Reviewed-on: #12
2025-03-12 10:13:58 +00:00
Max Martens
cd71fb3785 Merge branch 'feature/OVPAY-613-SE-productdetails' into develop 2025-03-11 13:11:26 +01:00
Max Martens
dc0435bb50 Change sellableTouchpointIds to lowercase P 2025-03-11 13:10:35 +01:00
Max Martens
b9c0408240 Merge remote-tracking branch 'origin/feature/OVPAY-612-SE-products-list' into develop 2025-03-07 11:36:21 +01:00
Max Martens
dcfdbeec34 Remove TP3 sellingPeriod that is not allowed to be seen by TP4 from examples 2025-03-06 15:29:20 +01:00
4f2543f57b Merge pull request 'features/correct-info-STUB-products-touchpoint=4' (#20) from features/correct-info-STUB-products-touchpoint=4 into feature/OVPAY-613-SE-productdetails
Reviewed-on: #20
2025-03-06 11:15:09 +00:00
Max Martens
0860a79267 Also persist changes in SE products yaml 2025-03-06 09:58:30 +01:00
Max Martens
11462b1608 Merge branch 'feature/OVPAY-613-SE-productdetails' into features/correct-info-STUB-products-touchpoint=4 2025-03-06 08:39:27 +01:00
Max Martens
3c4e567176 Merge branch 'develop' into feature/OVPAY-613-SE-productdetails 2025-03-06 08:13:59 +01:00
Max Martens
40d00ae61b Merge branch 'feature/OVPAY-613-SE-productdetails' into features/correct-info-STUB-products-touchpoint=4 2025-03-06 08:12:55 +01:00
Max Martens
712564001c Tweak examples to return empty arrays as [] instead of null 2025-03-06 08:05:09 +01:00
43ace0543c small fix for consistency 2025-03-05 14:35:40 +01:00
5864d43b0f added extra scenario 2025-03-05 14:31:39 +01:00
c712184e9f created correct example in the product list for touchpoint 4 (infoplaza) 2025-03-05 14:23:01 +01:00
dfb48bbcd1 Merge branch 'feature/OVPAY-613-SE-productdetails' of https://git.integratielaag.nl/HTM/ovpay into features/correct-info-STUB-products-touchpoint=4 2025-03-05 14:16:33 +01:00
c8368ab003 OVPAY-1518 - Changed GET query params to OData. 2025-03-05 14:08:57 +01:00
8eb6ebc29d Merge pull request 'features/OVPAY-1566' (#17) from features/OVPAY-1566 into develop
Reviewed-on: #17
2025-03-05 10:56:23 +00:00
6e5a903331 merged develop 2025-03-05 11:55:33 +01:00
3867478718 fixed my search&replace errors 2025-03-05 11:42:50 +01:00
e2c768804a fixed semantic error CRUD order 2025-03-05 10:48:09 +01:00
151a23c39a OVPAY-1518 - Added priority to endpoints. 2025-03-05 10:23:49 +01:00
bed4dddf3b OVPAY-1518 - Replaced asterisk by query param. 2025-03-04 12:42:01 +01:00
976293e617 OVPAY-1563 - Added query param contractInvoiceId. 2025-03-04 10:55:20 +01:00
dc4674202a OVPAY-1562 - Added query param resourceNameId. 2025-03-04 10:16:51 +01:00
2350b40e9b OVPAY-1518 - Added sort, limit, offset query params to GET operations. 2025-03-03 16:20:40 +01:00
18ffc699c7 OVPAY-1518 - Obfuscate names. 2025-03-03 14:23:23 +01:00
cd828981c5 OVPAY-1518 - Fixed bug in SourceMetadataPostRequestBody. 2025-03-03 14:14:24 +01:00
2b754dfb75 OVPAY-1518 - TaxPercentageAmount is a number. 2025-03-03 14:10:28 +01:00
d39a4ba51d OVPAY-1518 - No more seagulls. 2025-03-03 12:34:26 +01:00
Max Martens
cc7da9d69e Split up Swagger in two separate files with SE and TP URI, to accommodate two separate stubs 2025-02-27 16:33:52 +01:00
bd3f3e68a6 Addede delete address to CRUD 2025-02-26 16:17:17 +01:00
8461b117bd added delete on order address 2025-02-26 16:11:39 +01:00
2bf79f1fa0 versionering and additional remarks 2025-02-26 15:53:12 +01:00
Max Martens
c21f8f9e34 Add example showing how to handle null attributes 2025-02-26 09:41:47 +01:00
Max Martens
9b00a42d5d Fix URI 2025-02-24 16:49:14 +01:00
8c470c790c small fix 2025-02-24 15:54:37 +01:00
f190a007b8 mandate create in crud 2025-02-24 14:23:16 +01:00
76c5fd1804 v3.0 orders 2025-02-24 13:59:28 +01:00
caf927cae5 creating orderv2.3 2025-02-24 12:16:41 +01:00
db12ae5f62 added sort query param 2025-02-21 16:53:17 +01:00
c9b445b54b removed duplicate bic 2025-02-21 14:57:42 +01:00
12126253ac changed swift to bic inline with orders 2025-02-21 14:29:32 +01:00
67109e7217 pagination examples 2025-02-21 12:43:12 +01:00
298f089d6c added billing information CRUD en some tidying 2025-02-21 11:33:54 +01:00
030f4a2087 OVPAY-1518 - Minor documentation improvements. 2025-02-20 13:20:14 +01:00
40795f380a OVPAY-1518 - Added POST and PATCH examples for Processing Failure v2. 2025-02-20 13:11:36 +01:00
d496370cbe OVPAY-1518 - Added POST and PATCH examples for Metadata v2. 2025-02-20 11:48:14 +01:00
d0f2335acb OVPAY-1518 - Added POST and PATCH exampels for Booking Processes v2. 2025-02-20 11:26:50 +01:00
5fc879d685 OVPAY-1518 - Added final GET examples. 2025-02-20 10:38:01 +01:00
4a123f11ee OVPAY-1518 - Added GET /transactionitems/responsestatus/* 2025-02-20 10:05:40 +01:00
972219271e OVPAY-1518 - Added examples for GET Booking Processes v2. 2025-02-19 18:04:11 +01:00
7b2cf2f579 OVPAY-1518 - Added examples for Audit Trail v2. 2025-02-19 15:30:17 +01:00
71ab5176b5 OVPAY-1518 - Added examples for GET Metadata v2. 2025-02-19 13:39:49 +01:00
8e77c34615 OVPAY-1518 - Added examples for Transactions v2. 2025-02-19 11:18:03 +01:00
9106b99988 Merge pull request 'feature/OVPAY-1518' (#16) from feature/OVPAY-1518 into develop
Reviewed-on: #16
2025-02-18 15:39:00 +00:00
19afac017d OVPAY-1518 - Swapped concessionId. 2025-02-18 14:58:45 +01:00
36a2ccb03c OVPAY-1518 - Processed review remarks from data architect. 2025-02-18 14:51:44 +01:00
8b41cbd7c8 OVPAY-1518 - Bugfix. 2025-02-18 13:32:10 +01:00
3c25c250c2 OVPAY-1518 - Added endpoints for booking processes. 2025-02-18 13:28:44 +01:00
aa813cdabe OVPAY-1518 - Metadata audit trails are deprecated in favor of Elastik. 2025-02-18 11:28:50 +01:00
fd2ae8fa65 OVPAY-1518 - Removed legacy metadata 2. 2025-02-18 11:27:19 +01:00
7a50655408 OVPAY-1518 - Removed legacy metadata. 2025-02-18 11:15:41 +01:00
b115c0aed8 OVPAY-1518 - Updated /transactionitems. 2025-02-18 10:55:21 +01:00
683b12f6eb started on mandates 2025-02-17 17:44:50 +01:00
8f8a044fde tokens 2025-02-17 14:26:37 +01:00
028f970130 tokens 2025-02-17 14:22:39 +01:00
8463961f60 phones 2025-02-17 12:43:19 +01:00
b3d8d0d053 phones 2025-02-17 12:38:13 +01:00
c6b53d46ac phones 2025-02-17 12:37:13 +01:00
6c229b48b3 phone 2025-02-17 12:35:20 +01:00
dcb7d1b564 address 2025-02-17 12:04:17 +01:00
0ea5d1532a address 2025-02-17 11:55:32 +01:00
96f77d8f2f customerStatus 2025-02-17 11:16:55 +01:00
Max Martens
bfb62d7822 Fix parentProducId, remove customerSegments 2025-02-12 17:27:34 +01:00
5ebc012ceb updated existing CRUD with valid examples for stub 2025-02-10 17:46:17 +01:00
Max Martens
d87b3bb381 Fix productGroupMetadata in examples 2025-02-10 17:12:54 +01:00
Max Martens
5fab4e8dcc Process feedback
Remove 403 error description, add 404 example in correct RFC9457 format, refactor example labels, remove non-occurring errors
2025-02-10 17:05:40 +01:00
Max Martens
5ef6777aad Merge branch 'develop' into feature/OVPAY-613-SE-productdetails 2025-02-10 15:05:18 +01:00
b0e4a73d9a Merge pull request 'OVPAY-1433 - Added order fulfillment and order creation v2.2.' (#14) from feature/OVPAY-1433 into develop
Reviewed-on: #14
2025-02-10 12:50:44 +00:00
2bb61cbe98 Merge branch 'develop' into feature/OVPAY-1433 2025-02-10 12:49:08 +00:00
90e493fb07 OVPAY-1518 - Update TransactionAuditTrails. 2025-02-06 12:48:13 +01:00
7a5a6685b5 OVPAY-1518 - Update ProcessingFailures. 2025-02-06 12:11:14 +01:00
0d61d06198 OVPAY-1518 - Update TransactionItems data mode. 2025-02-06 10:49:44 +01:00
Max Martens
30bf97ba7a Add examples for productdetails tree with one and two-layer depth 2025-02-05 14:17:03 +01:00
Max Martens
024e14f31c Remove some remaining pagination stuff, add Regio Vrij details example, add more explanation and example descriptions 2025-02-05 13:48:50 +01:00
158cac33ed Merge pull request 'feature/OVPAY-612-SE-products-list' (#13) from feature/OVPAY-612-SE-products-list into develop
Reviewed-on: #13
2025-02-05 09:36:28 +00:00
3f4001ed4d OVPAY-1433 - Fulfillment now accepts externalOrderId and externalOrderLineId. 2025-02-03 14:56:01 +01:00
c6a5a456dd OVPAY-1433 - Removed touchPointId from v2.2. 2025-02-03 13:46:43 +01:00
2a1641cd4a OVPAY-1433 - Removed customerProfileId from v2.2. 2025-02-03 13:28:00 +01:00
1b0a6ba208 OVPAY-879 - Update FIKO bulk endpoint. 2025-01-28 13:48:44 +01:00
093b826f2b OVPAY-1433 - Added order fulfillment and order creation v2.2. 2025-01-28 11:00:09 +01:00
023bcf8aa5 Merge pull request 'feature/OVPAY-1210' (#9) from feature/OVPAY-1210 into develop
Reviewed-on: #9
2025-01-27 14:57:37 +00:00
2c9fcfef59 Merge branch 'develop' into feature/OVPAY-1210 2025-01-27 14:56:38 +00:00
Max Martens
2c07cc192b SE Products List endpoint spec 2025-01-24 13:39:50 +01:00
Max Martens
843256cb13 Merge branch 'feature/OVPAY-1210' into feature/OVPAY-612-SE-products-list 2025-01-24 13:13:09 +01:00
997d3e1d0e OVPAY-1352 - Added InvoiceAccountingStatus. 2025-01-20 11:09:26 +01:00
8f8edfacb0 OVPAY-526 - Add single transaction is deprecated. 2025-01-16 13:08:06 +01:00
04d251a3e2 Typo in serviceReferenceId example 2025-01-16 11:25:01 +01:00
b869b712a2 OVPAY-526 - Added external endpoints. 2025-01-16 10:44:36 +01:00
89fb3c8e1d Merge branch 'develop' of https://git.integratielaag.nl/HTM/ovpay into develop 2025-01-14 17:07:11 +01:00
5fb74ece06 Added refunds endpoint to ClaimsAPI. 2025-01-14 17:07:01 +01:00
8af1bed739 Merge pull request 'feature/OVPAY-96' (#8) from feature/OVPAY-96 into develop
Reviewed-on: #8
2025-01-09 16:30:24 +00:00
19ecad4a1d Merge branch 'develop' into feature/OVPAY-96 2025-01-09 16:29:51 +00:00
f44cb89138 billing alias example updated 2025-01-06 16:50:16 +01:00
8a5aba4bf5 added additional query params 2025-01-06 15:46:35 +01:00
3994e0ea90 semantic errors 2025-01-06 15:19:00 +01:00
fcc0740130 query params 2025-01-06 15:16:27 +01:00
42dce39642 first fixes 2025-01-06 12:41:45 +01:00
520362ae4d OVPAY-879 - Metadata v2 overhaul. 2025-01-03 16:07:43 +01:00
2515f36afa OVPAY-879 - Audit Trail v2 overhaul. 2024-12-24 14:36:29 +01:00
4ed63a75bf OVPAY-879 - Added schemas for Failures v2. 2024-12-24 13:27:22 +01:00
8111b631f3 OVPAY-879 - Added schemas for Transactions v2. 2024-12-24 11:31:10 +01:00
233c7114b9 OVPAY-879 - Minor fixes. 2024-12-24 09:35:30 +01:00
c595e25731 Added support for YAML and JSON files. 2024-12-23 09:00:31 +01:00
dbf8bff976 Tampermonkey plugin for adding a Swagger button to Gitea. 2024-12-20 15:25:34 +01:00
27351f1101 more stuff 2024-12-19 11:58:36 +01:00
dad9ece546 stuff 2024-12-19 11:55:25 +01:00
c5fa6746a2 hoofdentiteit volgens specs 2024-12-19 11:49:39 +01:00
cb0c79f68c removed to much 2024-12-19 11:47:23 +01:00
0c6c93a507 removed unnecessary schema's 2024-12-19 09:56:15 +01:00
10a4147869 fixed semantic error 2024-12-19 09:48:48 +01:00
6526db8a1d updated get customer list + get customer to include all query params and correct ref objects in response 2024-12-18 21:28:12 +01:00
1f04619ff7 added current state of customers CRUD as on WSO2 atm 2024-12-18 16:04:37 +01:00
Max Martens
ae387e822c Update description 2024-12-16 17:26:38 +01:00
Max Martens
53aa8cc62c Typo 2024-12-16 17:25:09 +01:00
Max Martens
d0acf2b465 Add optional parentProductId query parameter 2024-12-16 17:23:41 +01:00
e818ab6489 OVPAY-879 - Converted search params to array. 2024-12-11 16:09:59 +01:00
9c17102d04 OVPAY-879 - Small changes to cost center. 2024-12-11 13:56:27 +01:00
1f54500185 Merge branch 'main' into develop 2024-12-06 15:41:44 +01:00
Max Martens
3d415ab5ab Merge branch 'develop' into feature/OVPAY-96 2024-12-05 15:48:10 +01:00
Max Martens
89b5f0a169 Write logs to file, add color to Console logs, ignore logfiles from Git 2024-12-05 15:47:56 +01:00
Max Martens
ee8cdfc660 Remove _templates, add self under _links, add some new links and attributes 2024-12-05 15:23:37 +01:00
Max Martens
53adc797a1 Merge branch 'develop' into feature/OVPAY-96 2024-12-05 14:52:29 +01:00
Max Martens
7c666aa351 RC1 2024-12-04 17:40:58 +01:00
Max Martens
5c83fff7bf Java RabbitMQ POC project
Ugly and hardcoded, as a POC should be
2024-12-04 16:32:34 +01:00
Max Martens
a6878b9a34 WIP 3 2024-12-04 16:03:10 +01:00
107d5fac84 OVPAY-108 Added /orders endpoint for SE. 2024-12-03 16:48:54 +01:00
Max Martens
c04530e616 Process comments 2024-12-03 15:40:40 +01:00
Max Martens
33eef638d2 WIP update 2024-12-03 09:43:43 +01:00
Max Martens
feaaec2a53 WIP GET customers, GET OvPayTokens with HATEOAS 2024-12-03 09:00:49 +01:00
3eb98b0d23 Update src/openapi/customers/SE-customers.yaml
Added Get Customer V2- first draft
2024-12-02 14:59:28 +00:00
c000bf1e6e OVPAY-879 - Added bodies for creating trx. 2024-12-02 14:03:58 +01:00
013553fba2 Merge pull request 'feature/OVPAY-1145 - add tokenTypes array to ABTProducts list response model' (#7) from feature/OVPAY-1145 into develop
Reviewed-on: #7
2024-12-02 10:02:29 +00:00
9cde41bfc3 Update customer YAMLs on develop. 2024-12-02 10:58:46 +01:00
98babaeb91 Merge pull request 'OVPAY-754 - Added find on directdebitmandate.' (#3) from feature/OVPAY-754 into develop
Reviewed-on: #3
2024-12-02 09:46:28 +00:00
bfea9a5967 OVPAY-754 - Fixed PR remarks. Thanks maks. 2024-12-02 10:46:08 +01:00
9e5e782192 Merge pull request 'OVPAY-1201 - Minor delta on data model.' (#6) from feature/OVPAY-1201 into develop
Reviewed-on: #6
Reviewed-by: Max Martens <m.martens@htm.nl>
2024-12-02 09:36:19 +00:00
2e0df0f57c Merge pull request 'feature/OVPAY-1147' (#1) from feature/OVPAY-1147 into develop
Reviewed-on: #1
Reviewed-by: Max Martens <m.martens@htm.nl>
2024-12-02 09:35:47 +00:00
8e2ad79b53 OVPAY-1147 - Added pagination. 2024-11-26 15:34:55 +01:00
24a4ac14d2 OVPAY-1116 - Fixed typos. 2024-11-26 15:21:43 +01:00
13ad3afff0 OVPAY-1116 - Fixed typo. 2024-11-26 15:14:41 +01:00
bc745034ff OVPAY-1116 - Fixed POST. 2024-11-26 15:13:53 +01:00
4646f528b1 OVPAY-1116 - Added pagination. 2024-11-26 15:03:05 +01:00
bca4381de7 OVPAY-680 - Fixed typo. 2024-11-26 12:37:58 +01:00
b042c901e7 OVPAY-680 - Added interface voor contract cancellation pt.2. 2024-11-26 12:28:52 +01:00
f9f22f4ccd OVPAY-680 - Added interface voor contract cancellation. 2024-11-26 12:21:58 +01:00
Max Martens
eab79163cf First commit, still WIP 2024-11-25 17:03:28 +01:00
9041fb5bf9 OVPAY-879 - Update after feedback Almando. 2024-11-22 13:43:18 +01:00
e7559c76e5 OVPAY-1116 - Fixed typo. 2024-11-22 11:01:30 +01:00
f065cb8072 OVPAY-108 - Fixed JSON error. 2024-11-21 11:10:48 +01:00
3b390e0c6e OVPAY-108 - Added info for SMP. 2024-11-19 15:53:30 +01:00
889eeeb130 OVPAY-1136 - Added API versioning in HTTP headers. 2024-11-19 14:46:13 +01:00
cb6f1f6f48 OVPAY-1116 - Added missing fields. 2024-11-18 14:05:08 +01:00
Max Martens
6d9712cdeb Merge branch 'develop' into feature/OVPAY-1145 2024-11-18 13:15:03 +01:00
5306f34daf OVPAY-1201 - Minor delta on data model. 2024-11-13 14:40:03 +01:00
1f9e9c83ac OVPAY-108 - Simplified list orders operation. 2024-11-13 14:24:33 +01:00
0dabe48807 OVPAY-1180 - Added role and user to crud apis. 2024-11-07 14:16:25 +01:00
85c9872e19 Merge pull request 'develop' (#5) from develop into main
Reviewed-on: #5
2024-11-07 12:43:22 +00:00
35063ab2ee Merge branch 'main' into develop 2024-11-07 12:43:16 +00:00
f45d83e3e3 Merge pull request 'feature/OVPAY-1126' (#2) from feature/OVPAY-1126 into develop
Reviewed-on: #2
2024-11-07 12:42:22 +00:00
0f5fb627cd OVPAY-1126 - Filled patch /orders. 2024-11-07 13:41:53 +01:00
989b47a2d1 Add address as single entity to order customer. 2024-11-07 10:36:13 +01:00
e242e4db54 OVPAY-1126 - Renamed tag v2 to v2.1. 2024-11-06 16:18:44 +01:00
9be5af4886 OVPAY-1126 - Added fulfillment for SMP. 2024-11-06 16:16:24 +01:00
aa0d341b24 Merge branch 'feature/OVPAY-1126' of https://git.integratielaag.nl/HTM/ovpay into feature/OVPAY-1126 2024-11-06 15:54:12 +01:00
40da8531ed OVPAY-1172 - Return current state of order object in fulfillment v2. 2024-11-06 15:53:26 +01:00
bb478aa231 OVPAY-1126 - Specified endpoints for Order Creation and Order Retrieval for touch point. 2024-11-06 15:53:26 +01:00
7174f2942a OVPAY-1126 - Added deletes on order and order line. 2024-11-06 15:53:26 +01:00
836a884cfd OVPAY-1172 - Return current state of order object in fulfillment v2. 2024-11-04 15:55:50 +01:00
f7a56f3e62 OVPAY-754 - Added find on directdebitmandate. 2024-10-25 13:27:47 +02:00
2b53158117 OVPAY-1126 - Specified endpoints for Order Creation and Order Retrieval for touch point. 2024-10-25 11:24:36 +02:00
197f1e07f6 OVPAY-1126 - Payments should always be added in single. 2024-10-25 09:57:04 +02:00
aac4254e2e OVPAY-1126 - Added deletes on order and order line. 2024-10-24 17:48:56 +02:00
330c7d1e2b OVPAY-1147 - Typo. 2024-10-24 15:23:48 +02:00
3b12204566 OVPAY-1147 - MediaType should be TokenType. 2024-10-24 15:23:09 +02:00
e534d7161b OVPAY-1147 - Init. 2024-10-21 09:57:47 +02:00
Max Martens
b020a02c82 OVPAY-1145 - add tokenTypes array to products list respnse model schema and examples 2024-10-17 19:24:28 +02:00
Max Martens
2621c6e180 Revert "Fix typo validTo -> validUntil"
This reverts commit 0ce44a5616.
2024-10-17 12:50:19 +02:00
Max Martens
0ce44a5616 Fix typo validTo -> validUntil 2024-10-17 12:24:29 +02:00
87c545c689 OVPAY-982 - Added 'isCredit' to CRUD API's. 2024-10-14 12:03:28 +02:00
72 changed files with 43767 additions and 3441 deletions

View File

@ -0,0 +1,307 @@
########################
## ##
## CUSTOM IGNORE LIST ##
## ##
########################
# Ignore appsettings.json as it contains credentials - only the template should be shared!
appsettings.json
# Also ignore pfx and pem files for the same reason
*.pfx
*.pem
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
# VS Code
.vscode/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs

View File

@ -0,0 +1,614 @@
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using Microsoft.AspNetCore.Http.HttpResults;
class ApimHelper
{
private readonly string _apimBaseUri;
private readonly string _b2bApiUri;
private readonly string _padp1201Uri;
private readonly string _padp1202Uri;
private readonly string _padp1204Uri;
private readonly string _padp1205Uri;
private readonly string _padp1206V2Uri;
private readonly string _padp1207V2Uri;
private readonly string _padp1206V3Uri;
private readonly string _padp1207V3Uri;
private readonly string _padp1210Uri;
private readonly string _padp1211Uri;
private readonly string _b2bApiKey;
private readonly string _padApiKey;
private readonly string _clientId;
private readonly string _clientSecret;
private CryptoHelper cryptoHelper;
private readonly HttpClient _httpClient;
private Dictionary<string, UserAuthInfo> userAuthInfoMap = new Dictionary<string, UserAuthInfo>();
public ApimHelper(UserProperties userProperties)
{
_apimBaseUri = userProperties.Uris.ApimBaseUri;
_b2bApiUri = userProperties.Uris.B2bApiUri;
_padp1201Uri = userProperties.Uris.Padp1201Uri;
_padp1202Uri = userProperties.Uris.Padp1202Uri;
_padp1204Uri = userProperties.Uris.Padp1204Uri;
_padp1205Uri = userProperties.Uris.Padp1205Uri;
_padp1206V2Uri = userProperties.Uris.Padp1206V2Uri;
_padp1207V2Uri = userProperties.Uris.Padp1207V2Uri;
_padp1206V3Uri = userProperties.Uris.Padp1206V3Uri;
_padp1207V3Uri = userProperties.Uris.Padp1207V3Uri;
_padp1210Uri = userProperties.Uris.Padp1210Uri;
_padp1211Uri = userProperties.Uris.Padp1211Uri;
_b2bApiKey = userProperties.Credentials.B2bApiKey;
_padApiKey = userProperties.Credentials.PadApiKey;
_clientId = userProperties.Credentials.ClientId;
_clientSecret = userProperties.Credentials.ClientSecret;
cryptoHelper = new CryptoHelper(userProperties);
HttpClientHandler handler = new HttpClientHandler();
string clientCertPath = Environment.CurrentDirectory + userProperties.Credentials.ClientCertFile;
Console.WriteLine("Loading client cert from: {0}", clientCertPath);
handler.ClientCertificates.Add(new X509Certificate2(clientCertPath, userProperties.Credentials.ClientCertPassword));
_httpClient = new HttpClient(handler);
_httpClient.BaseAddress = new Uri(_apimBaseUri);
}
public async Task<Results<Ok<B2bAccessToken>, JsonHttpResult<ErrorResponse>>> GetB2bAccessToken()
{
var request = new HttpRequestMessage(HttpMethod.Post, _b2bApiUri);
request.Headers.Add("APIKey", _b2bApiKey);
request.Headers.Add("Accept", "application/json");
request.Content = new StringContent($"grant_type=client_credentials&client_id={_clientId}&client_secret={_clientSecret}", Encoding.UTF8, "application/x-www-form-urlencoded");
Console.WriteLine("Sending request to {0}...", _b2bApiUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK) {
return TypedResults.Ok(await response.Content.ReadFromJsonAsync<B2bAccessToken>());
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
private string GetB2bAccessTokenAsString()
{
var b2bAccessToken = GetB2bAccessToken();
return ((Ok<B2bAccessToken>)b2bAccessToken.Result.Result).Value.accessToken;
}
public IResult GetImageFromBase64(string base64Image)
{
byte[] imageBytes = Convert.FromBase64String(base64Image);
return TypedResults.File(imageBytes, "image/jpeg");
}
public async Task<Results<Created, JsonHttpResult<ErrorResponse>>> CreatePersonalData(string xTat, string email, string? name, string? birthDate, IFormFile? photo)
{
UserAuthInfo userAuthInfo;
if (userAuthInfoMap.TryGetValue(xTat, out UserAuthInfo? authInfo) && authInfo.encryptedEphemeralKey != null) {
userAuthInfo = authInfo;
} else {
var errorResponse = new ErrorResponse("No ephemeral key found for xTAT " + xTat + " - generate and validate OTP first using API 1210!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
var b2bAccessToken = await GetB2bAccessToken();
var requestUri = _padp1201Uri.Replace("{xtat}", xTat);
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Headers.Add("Authorization", "Bearer " + ((Ok<B2bAccessToken>)b2bAccessToken.Result).Value.accessToken);
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
var createPersonalDataRequest = new CreatePersonalDataRequest();
createPersonalDataRequest.metadata.email = email;
createPersonalDataRequest.metadata.ephemeralKeyAlias = userAuthInfo.ephemeralKeyAlias;
var decryptedEphemeralKey = cryptoHelper.DecryptEphemeralKey(userAuthInfo.encryptedEphemeralKey);
if (name != null) {
createPersonalDataRequest.data.personalAccountData.name = cryptoHelper.EncryptText(decryptedEphemeralKey, name);
}
if (birthDate != null) {
createPersonalDataRequest.data.personalAccountData.birthdate = cryptoHelper.EncryptText(decryptedEphemeralKey, birthDate);;
}
if (photo != null) {
using (MemoryStream memoryStream = new MemoryStream())
{
photo.CopyTo(memoryStream);
byte[] photoBytes = memoryStream.ToArray();
createPersonalDataRequest.data.personalAccountData.photo = cryptoHelper.EncryptPhoto(decryptedEphemeralKey, photoBytes);
}
}
request.Content = JsonContent.Create(createPersonalDataRequest);
Console.WriteLine("Sending request to {0} with request body {1}...", requestUri, request.Content.ReadAsStringAsync().Result);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Created) {
return TypedResults.Created();
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<Created, JsonHttpResult<ErrorResponse>>> CreatePersonalDataWithEmailVerification(string xTat, string email, string? userAccessToken, string? name, string? birthDate, IFormFile? photo)
{
UserAuthInfo userAuthInfo;
if (userAuthInfoMap.TryGetValue(xTat, out UserAuthInfo? authInfo)) {
if (authInfo.encryptedEphemeralKey == null) {
var errorResponse = new ErrorResponse("No ephemeral key found for xTAT " + xTat + " - generate an ephemeral key first, using API 1210!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
} else if (authInfo.UserAccessToken == null && userAccessToken == null) {
var errorResponse = new ErrorResponse("No User Access Token found for xTAT " + xTat + " - provide one in the request, or generate and validate OTP using API 1206 and 1207!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
userAuthInfo = authInfo;
} else {
var errorResponse = new ErrorResponse("No ephemeral key found for xTAT " + xTat + " - generate an ephemeral key first, using API 1210!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
var requestUri = _padp1201Uri.Replace("{xtat}", xTat);
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
if (userAccessToken != null) {
Console.WriteLine("Using provided User Access Token {0}...", userAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAccessToken);
} else {
Console.WriteLine("Using stored User Access Token {0}...", userAuthInfo.UserAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAuthInfo.UserAccessToken);
}
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
var createPersonalDataRequest = new CreatePersonalDataRequest();
createPersonalDataRequest.metadata.email = email;
createPersonalDataRequest.metadata.ephemeralKeyAlias = userAuthInfo.ephemeralKeyAlias;
var decryptedEphemeralKey = cryptoHelper.DecryptEphemeralKey(userAuthInfo.encryptedEphemeralKey);
if (name != null) {
createPersonalDataRequest.data.personalAccountData.name = cryptoHelper.EncryptText(decryptedEphemeralKey, name);
}
if (birthDate != null) {
createPersonalDataRequest.data.personalAccountData.birthdate = cryptoHelper.EncryptText(decryptedEphemeralKey, birthDate);;
}
if (photo != null) {
using (MemoryStream memoryStream = new MemoryStream())
{
photo.CopyTo(memoryStream);
byte[] photoBytes = memoryStream.ToArray();
createPersonalDataRequest.data.personalAccountData.photo = cryptoHelper.EncryptPhoto(decryptedEphemeralKey, photoBytes);
}
}
request.Content = JsonContent.Create(createPersonalDataRequest);
Console.WriteLine("Sending request to {0} with request body {1}...", requestUri, request.Content.ReadAsStringAsync().Result);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Created) {
return TypedResults.Created();
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<Ok<PersonalData>, JsonHttpResult<ErrorResponse>>> GetPersonalData(string xTat, string? userAccessToken)
{
UserAuthInfo? userAuthInfo = null;
if (userAuthInfoMap.TryGetValue(xTat, out UserAuthInfo? authInfo) && authInfo.UserAccessToken != null)
{
userAuthInfo = authInfo;
} else if (userAccessToken == null) {
var errorResponse = new ErrorResponse("No User Access Token found for xTAT " + xTat + " - provide one in the request, or generate and validate OTP using API 1206 and 1207!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
var requestUri = _padp1202Uri.Replace("{xtat}", xTat) + "?pemRsaPublicKey=" + cryptoHelper.GetPublicKeyRsa();
var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
if (userAccessToken != null)
{
Console.WriteLine("Using provided User Access Token {0}...", userAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAccessToken);
} else {
Console.WriteLine("Using stored User Access Token {0}...", userAuthInfo.UserAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAuthInfo.UserAccessToken);
}
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return TypedResults.Ok(await response.Content.ReadFromJsonAsync<PersonalData>());
}
else
{
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<Ok<DecryptedPersonalData>, JsonHttpResult<ErrorResponse>>> GetDecryptedPersonalData(string xTat, string? userAccessToken)
{
var personalData = await GetPersonalData(xTat, userAccessToken);
if (personalData.Result.GetType() == typeof(JsonHttpResult<ErrorResponse>)) {
return (JsonHttpResult<ErrorResponse>)personalData.Result;
} else {
var decryptedPersonalData = await DecryptPersonalData(((Ok<PersonalData>)personalData.Result).Value);
return TypedResults.Ok(decryptedPersonalData);
}
}
public async Task<Results<Ok<DeletePersonalDataResponse>, JsonHttpResult<ErrorResponse>>> DeletePersonalData(string xTat, string? userAccessToken)
{
UserAuthInfo? userAuthInfo = null;
if (userAuthInfoMap.TryGetValue(xTat, out UserAuthInfo? authInfo) && authInfo.UserAccessToken != null)
{
userAuthInfo = authInfo;
} else if (userAccessToken == null) {
var errorResponse = new ErrorResponse("No User Access Token found for xTAT " + xTat + " - provide one in the request, or generate and validate OTP using API 1206 and 1207!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
var requestUri = _padp1204Uri.Replace("{xtat}", xTat);
var request = new HttpRequestMessage(HttpMethod.Delete, requestUri);
if (userAccessToken != null) {
Console.WriteLine("Using provided User Access Token {0}...", userAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAccessToken);
} else {
Console.WriteLine("Using stored User Access Token {0}...", userAuthInfo.UserAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAuthInfo.UserAccessToken);
}
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK) {
return TypedResults.Ok(await response.Content.ReadFromJsonAsync<DeletePersonalDataResponse>());
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<Ok, JsonHttpResult<ErrorResponse>>> UpdatePersonalData(string xTat, string? userAccessToken, bool skipUpdateCounter, string? name, string? birthDate, IFormFile? photo)
{
UserAuthInfo userAuthInfo;
if (userAuthInfoMap.TryGetValue(xTat, out UserAuthInfo? authInfo)) {
if (authInfo.encryptedEphemeralKey == null) {
var errorResponse = new ErrorResponse("No ephemeral key found for xTAT " + xTat + " - generate an ephemeral key first, using API 1210!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
} else if (authInfo.UserAccessToken == null && userAccessToken == null) {
var errorResponse = new ErrorResponse("No User Access Token found for xTAT " + xTat + " - provide one in the request, or generate and validate OTP using API 1206 and 1207!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
userAuthInfo = authInfo;
} else {
var errorResponse = new ErrorResponse("No User Access Token found for xTAT " + xTat + " - provide one in the request, or generate and validate OTP using API 1206 and 1207!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
var requestUri = _padp1205Uri.Replace("{xtat}", xTat);
var request = new HttpRequestMessage(HttpMethod.Put, requestUri);
if (userAccessToken != null) {
Console.WriteLine("Using provided User Access Token {0}...", userAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAccessToken);
} else {
Console.WriteLine("Using stored User Access Token {0}...", userAuthInfo.UserAccessToken);
request.Headers.Add("Authorization", "Bearer " + userAuthInfo.UserAccessToken);
}
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
var updatePersonalDataRequest = new UpdatePersonalDataRequest();
updatePersonalDataRequest.metadata.skipUpdateCounter = skipUpdateCounter;
updatePersonalDataRequest.metadata.ephemeralKeyAlias = userAuthInfo.ephemeralKeyAlias;
var decryptedEphemeralKey = cryptoHelper.DecryptEphemeralKey(userAuthInfo.encryptedEphemeralKey);
if (name != null) {
updatePersonalDataRequest.data.personalAccountData.name = cryptoHelper.EncryptText(decryptedEphemeralKey, name);
}
if (birthDate != null) {
updatePersonalDataRequest.data.personalAccountData.birthdate = cryptoHelper.EncryptText(decryptedEphemeralKey, birthDate);;
}
if (photo != null) {
using (MemoryStream memoryStream = new MemoryStream())
{
photo.CopyTo(memoryStream);
byte[] photoBytes = memoryStream.ToArray();
updatePersonalDataRequest.data.personalAccountData.photo = cryptoHelper.EncryptPhoto(decryptedEphemeralKey, photoBytes);
}
}
request.Content = JsonContent.Create(updatePersonalDataRequest);
Console.WriteLine("Sending request to {0} with request body {1}...", requestUri, request.Content.ReadAsStringAsync().Result);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK) {
return TypedResults.Ok();
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<JsonHttpResult<OtpResponse>, JsonHttpResult<ErrorResponse>>> GenerateOtpV2(string xTat)
{
var requestUri = _padp1206V2Uri.Replace("{xtat}", xTat);
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Headers.Add("Authorization", "Bearer " + GetB2bAccessTokenAsString());
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
request.Content = new StringContent("{\"channel\": \"EMAIL\"}", Encoding.UTF8, "application/json");
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Accepted) {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<OtpResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<Ok<UserAccessToken>, JsonHttpResult<ErrorResponse>>> ValidateOtpV2(string xTat, string otp)
{
var requestUri = _padp1207V2Uri.Replace("{xtat}", xTat);
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Headers.Add("Authorization", "Bearer " + GetB2bAccessTokenAsString());
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
request.Content = new StringContent("{\"otp\": \"" + otp + "\"}", Encoding.UTF8, "application/json");
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK) {
var content = await response.Content.ReadFromJsonAsync<UserAccessToken>();
Console.WriteLine("Successfully retrieved User Access Token for xTAT {0} - storing for use in following calls...", xTat);
if (!userAuthInfoMap.ContainsKey(xTat)) {
userAuthInfoMap.Add(xTat, new UserAuthInfo());
}
UserAuthInfo userAuthInfo = userAuthInfoMap[xTat];
userAuthInfo.UserAccessToken = content.accessToken;
return TypedResults.Ok(content);
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<JsonHttpResult<OtpResponse>, JsonHttpResult<ErrorResponse>>> GenerateOtpV3(string? email, string? xTat)
{
var requestUri = _padp1206V3Uri;
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Headers.Add("Authorization", "Bearer " + GetB2bAccessTokenAsString());
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
var generateOtpRequest = new GenerateOtpRequestV3();
generateOtpRequest.channel = "EMAIL";
if (email != null) {
generateOtpRequest.source = "EMAIL";
generateOtpRequest.recipient = email;
} else if (xTat != null) {
generateOtpRequest.source = "XTAT";
generateOtpRequest.recipient = xTat;
} else if (email != null && xTat != null){
var errorResponse = new ErrorResponse("Both e-mail and xTAT filled, only one should be filled in the request!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
request.Content = JsonContent.Create(generateOtpRequest);
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Accepted) {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<OtpResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<Ok<UserAccessToken>, JsonHttpResult<ErrorResponse>>> ValidateOtpV3(string? email, string? xTat, string otp)
{
var requestUri = _padp1207V3Uri;
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Headers.Add("Authorization", "Bearer " + GetB2bAccessTokenAsString());
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
var validateOtpRequest = new ValidateOtpRequestV3();
validateOtpRequest.otp = otp;
if (email != null)
{
validateOtpRequest.source = "EMAIL";
validateOtpRequest.recipient = email;
}
else if (xTat != null)
{
validateOtpRequest.source = "XTAT";
validateOtpRequest.recipient = xTat;
}
else if (email != null && xTat != null)
{
var errorResponse = new ErrorResponse("Both e-mail and xTAT filled, only one should be filled in the request!", 400);
return TypedResults.Json(errorResponse, JsonSerializerOptions.Default, "application/json", 400);
}
request.Content = JsonContent.Create(validateOtpRequest);
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK) {
var content = await response.Content.ReadFromJsonAsync<UserAccessToken>();
if (xTat != null) {
Console.WriteLine("Successfully retrieved User Access Token for xTAT {0} - storing for use in following calls...", xTat);
if (!userAuthInfoMap.ContainsKey(xTat))
{
userAuthInfoMap.Add(xTat, new UserAuthInfo());
}
UserAuthInfo userAuthInfo = userAuthInfoMap[xTat];
userAuthInfo.UserAccessToken = content.accessToken;
}
else {
Console.WriteLine("Successfully retrieved User Access Token for e-mail {0} - we don't know the xTAT (yet), so we don't cannot the user access token for later use...");
}
return TypedResults.Ok(content);
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public async Task<Results<Ok<AdministrativeData>, JsonHttpResult<ErrorResponse>>> GetAdministrativeData(string xTat)
{
var requestUri = _padp1211Uri.Replace("{xtat}", xTat);
var request = new HttpRequestMessage(HttpMethod.Get, requestUri);
request.Headers.Add("Authorization", "Bearer " + GetB2bAccessTokenAsString());
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
return TypedResults.Ok(await response.Content.ReadFromJsonAsync<AdministrativeData>());
}
else
{
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
public string EncryptDecryptPoc(string textToEncrypt, string encryptedEphemeralKey)
{
Console.WriteLine("Encrypting, then decrypting text {0} using encrypted ephemeral key {1}...", textToEncrypt, encryptedEphemeralKey);
var decryptedEphemeralKey = cryptoHelper.DecryptEphemeralKey(encryptedEphemeralKey);
var encryptedText = cryptoHelper.EncryptText(decryptedEphemeralKey, textToEncrypt);
Console.WriteLine($"Encrypted text: {encryptedText}");
Console.WriteLine("Decrypting text {0}...", encryptedText);
var decryptedText = cryptoHelper.DecryptTextAsync(decryptedEphemeralKey, encryptedText);
Console.WriteLine($"Decrypted text: {decryptedText.Result}");
return "Encrypted text: " + encryptedText + "\nDecrypted text: " + decryptedText.Result;
}
public string EncryptPoc(string textToEncrypt, string encryptedEphemeralKey)
{
Console.WriteLine("Encrypting text {0} using encrypted ephemeral key {1}...", textToEncrypt, encryptedEphemeralKey);
var decryptedEphemeralKey = cryptoHelper.DecryptEphemeralKey(encryptedEphemeralKey);
var encryptedText = cryptoHelper.EncryptText(decryptedEphemeralKey, textToEncrypt);
Console.WriteLine($"Encrypted text: {encryptedText}");
return "Encrypted text: " + encryptedText;
}
public string DecryptPoc(string textToDecrypt, string encryptedEphemeralKey)
{
Console.WriteLine("Decrypting text {0} using ephemeral key {1}...", textToDecrypt, encryptedEphemeralKey);
var decryptedEphemeralKey = cryptoHelper.DecryptEphemeralKey(encryptedEphemeralKey);
var decryptedText = cryptoHelper.DecryptTextAsync(decryptedEphemeralKey, textToDecrypt);
Console.WriteLine($"Decrypted text: {decryptedText.Result}");
return "Decrypted text: " + decryptedText.Result;
}
public async Task<Results<Ok<EphemeralKey>, JsonHttpResult<ErrorResponse>>> CreateEphemeralKey(string xTat)
{
var requestUri = _padp1210Uri + "?pemRsaPublicKey=" + cryptoHelper.GetPublicKeyRsa();
var request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Headers.Add("Authorization", "Bearer " + GetB2bAccessTokenAsString());
request.Headers.Add("APIKey", _padApiKey);
request.Headers.Add("requestId", Guid.NewGuid().ToString());
request.Headers.Add("Accept", "application/json");
Console.WriteLine("Sending request to {0}...", requestUri);
var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.Created) {
var content = await response.Content.ReadFromJsonAsync<EphemeralKey>();
Console.WriteLine("Successfully created Ephemeral Key for xTAT {0} - storing for use in following calls...", xTat);
if (!userAuthInfoMap.ContainsKey(xTat)) {
userAuthInfoMap.Add(xTat, new UserAuthInfo());
}
UserAuthInfo userAuthInfo = userAuthInfoMap[xTat];
userAuthInfo.ephemeralKeyAlias = content.ephemeralKeyAlias;
userAuthInfo.encryptedEphemeralKey = content.encryptedEphemeralKey;
return TypedResults.Ok(content);
} else {
return TypedResults.Json(await response.Content.ReadFromJsonAsync<ErrorResponse>(), JsonSerializerOptions.Default, "application/json", (int)response.StatusCode);
}
}
private async Task<DecryptedPersonalData> DecryptPersonalData(PersonalData personalData)
{
var decryptedEphemeralKey = cryptoHelper.DecryptEphemeralKey(personalData.metadata.encryptedEphemeralKey);
Console.WriteLine("Decrypted encryptedEphemeralKey: {0}", Convert.ToBase64String(decryptedEphemeralKey));
var decryptedData = new DecryptedPersonalData.DecryptedData();
if (personalData.data.name != null) {
decryptedData.decryptedName = await cryptoHelper.DecryptTextAsync(decryptedEphemeralKey, personalData.data.name);
Console.WriteLine($"Decrypted name: {decryptedData.decryptedName}");
}
if (personalData.data.birthdate != null) {
decryptedData.decryptedBirthdate = await cryptoHelper.DecryptTextAsync(decryptedEphemeralKey, personalData.data.birthdate);
Console.WriteLine($"Decrypted birthDate: {decryptedData.decryptedBirthdate}");
}
if (personalData.data.photo != null) {
decryptedData.decryptedPhoto = await cryptoHelper.DecryptPhotoAsync(decryptedEphemeralKey, personalData.data.photo);
Console.WriteLine($"Decrypted photo: {decryptedData.decryptedPhoto}");
}
return new DecryptedPersonalData(decryptedData, personalData);
}
}

View File

@ -0,0 +1,124 @@
using System.Security.Cryptography;
using System.Text;
public class CryptoHelper
{
private RSA rsa;
private string _publicKeyRsa;
public CryptoHelper(UserProperties userProperties)
{
string publicKeyPath = Environment.CurrentDirectory + userProperties.Rsa.PublicKeyFile;
string privateKeyPath = Environment.CurrentDirectory + userProperties.Rsa.PrivateKeyFile;
Console.WriteLine("Loading public key from: {0}", publicKeyPath);
Console.WriteLine("Loading private key from: {0}", privateKeyPath);
rsa = RSA.Create();
rsa.ImportFromPem(File.ReadAllText(publicKeyPath));
rsa.ImportFromPem(File.ReadAllText(privateKeyPath));
_publicKeyRsa = Convert.ToBase64String(rsa.ExportSubjectPublicKeyInfo());
}
public string GetPublicKeyRsa() => _publicKeyRsa;
public byte[] DecryptEphemeralKey(string encryptedEphemeralKey)
{
return rsa.Decrypt(Convert.FromBase64String(encryptedEphemeralKey), RSAEncryptionPadding.OaepSHA512);
}
public async Task<string> DecryptTextAsync(byte[] decryptedEphemeralKey, string encryptedText)
{
var decryptedBytes = await DecryptContentAsync(decryptedEphemeralKey, encryptedText);
return Encoding.UTF8.GetString(decryptedBytes);
}
public async Task<string> DecryptPhotoAsync(byte[] decryptedEphemeralKey, string encryptedPhoto)
{
var decryptedBytes = await DecryptContentAsync(decryptedEphemeralKey, encryptedPhoto);
return Convert.ToBase64String(decryptedBytes);
}
public string EncryptText(byte[] decryptedEphemeralKey, string textValue)
{
return EncryptContent(decryptedEphemeralKey, Encoding.UTF8.GetBytes(textValue));
}
public string EncryptPhoto(byte[] decryptedEphemeralKey, byte[] photoBytes)
{
return EncryptContent(decryptedEphemeralKey, photoBytes);
}
private async Task<byte[]> DecryptContentAsync(byte[] decryptedEphemeralKey, string encryptedData)
{
byte[] encryptedDataByteArray = Convert.FromBase64String(encryptedData);
using MemoryStream memoryStream = new(encryptedDataByteArray);
using Aes aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
byte[] iv = new byte[aes.IV.Length];
int numBytesToRead = aes.IV.Length;
int numBytesRead = 0;
while (numBytesToRead > 0)
{
int n = memoryStream.Read(iv, numBytesRead, numBytesToRead);
if (n == 0)
{
break;
}
numBytesRead += n;
numBytesToRead -= n;
}
byte[] key = decryptedEphemeralKey;
await using CryptoStream cryptoStream = new(memoryStream,
aes.CreateDecryptor(key, iv),
CryptoStreamMode.Read);
using MemoryStream ms = new();
await cryptoStream.CopyToAsync(ms);
var bytes = ms.ToArray();
return bytes;
}
private string EncryptContent(byte[] decryptedEphemeralKey, byte[] content)
{
byte[] encrypted;
byte[] iv;
using (var aesAlg = Aes.Create())
{
aesAlg.Key = decryptedEphemeralKey;
aesAlg.GenerateIV();
iv = aesAlg.IV;
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
// Create an encryptor to perform the stream transform.
var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new())
{
using (CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write))
{
//Write all data to the stream.
csEncrypt.Write(content, 0, content.Length);
}
encrypted = msEncrypt.ToArray();
}
}
var combinedIvCt = new byte[iv.Length + encrypted.Length];
Array.Copy(iv, 0, combinedIvCt, 0, iv.Length);
Array.Copy(encrypted, 0, combinedIvCt, iv.Length, encrypted.Length);
var encryptedData = Convert.ToBase64String(combinedIvCt);
return encryptedData;
}
}

View File

@ -0,0 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.14" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="8.0.0" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,250 @@
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(setupAction =>
{
setupAction.EnableAnnotations();
setupAction.SchemaFilter<SwaggerSchemaExampleFilter>();
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
var group = app.MapGroup("/").DisableAntiforgery().WithTags("PADP Reference API");
var pocGroup = app.MapGroup("/poc").DisableAntiforgery().WithTags("Encrypt/decrypt POC");
UserProperties userProperties = app.Configuration.GetSection("UserProperties").Get<UserProperties>();
ApimHelper apimHelper = new ApimHelper(userProperties);
group.MapGet("/idp/b2b-access-token", () =>
{
return apimHelper.GetB2bAccessToken();
})
.Produces<B2bAccessToken>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("GetB2bAccessToken")
.WithSummary("API 1020 - Get B2B Access Token")
.WithDescription("Returns a client access token, needed for most other PADP APIs.")
.WithOpenApi();
group.MapGet("/get-image-from-base64", ([FromHeader]string base64String) =>
{
return apimHelper.GetImageFromBase64(base64String);
})
.Produces<FileContentHttpResult>(200, "image/jpeg")
.WithName("GetImageFromBase64")
.WithSummary("Get rendered image from Base64 encoded String")
.WithOpenApi();
group.MapPost("/personal-data/{xtat}", (string xTat, [SwaggerParameter("Email address to be used for OTP challenges")] string email, [SwaggerParameter("Should be at least two words (first name and last name)")] string? name, [SwaggerParameter("Should be a date between 1900-01-01 and now, in the format YYYY-MM-DD")] string? birthDate, [SwaggerSchema("Should be a JPG image, of max. 512KB and resolution between 520x520 and 720x720")] IFormFile? photo) =>
{
Console.WriteLine("Creating personal data for xTAT: " + xTat);
return apimHelper.CreatePersonalData(xTat, email, name, birthDate, photo);
})
.Produces(201)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("CreatePersonalData")
.WithSummary("API 1201 - Create Personal Data - First create an ephemeral key using API 1210!")
.WithDescription("First create an ephemeral key using API 1210!")
.WithOpenApi();
group.MapPost("/personal-data/{xtat}/with-email-verification", (string xTat, [SwaggerParameter("Email address to be used for OTP challenges")]string email, [SwaggerParameter("This user access token will be used for e-mail verification if provided - otherwise, the internally stored one (based on previous V3 1206+1207 calls) will be used")]string? userAccessToken, [SwaggerParameter("Should be at least two words (first name and last name)")]string? name, [SwaggerParameter("Should be a date between 1900-01-01 and now, in the format YYYY-MM-DD")]string? birthDate, [SwaggerSchema("Should be a JPG image, of max. 512KB and resolution between 520x520 and 720x720")]IFormFile? photo) =>
{
Console.WriteLine("Creating personal data with e-mail verification for xTAT: " + xTat);
return apimHelper.CreatePersonalDataWithEmailVerification(xTat, email, userAccessToken,name, birthDate, photo);
})
.Produces(201)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("CreatePersonalDataWithEmailVerification")
.WithSummary("API 1201 - Create Personal Data with e-mail verification - First create an ephemeral key using API 1210!")
.WithDescription("Performs extra e-mail verification using OTP flow; using internally stored (after 1206+1207 call) or explicitly provided user access token. First create an ephemeral key using API 1210!")
.WithOpenApi();
group.MapGet("/personal-data/{xtat}", (string xTat, [SwaggerParameter("If provided, this user access token will be used over the internally stored one (that was restrieved via earlier 1206+1207 calls)")]string? userAccessToken) =>
{
Console.WriteLine("Retrieving personal data for xTAT: " + xTat);
return apimHelper.GetPersonalData(xTat, userAccessToken);
})
.Produces<PersonalData>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("GetPersonalData")
.WithSummary("API 1202 - Get Personal Data - First perform an OTP challenge using API 1206 and 1207 or explicitly provide user access token!")
.WithDescription("First perform an OTP challenge using API 1206 and 1207 or explicitly provide user access token!")
.WithOpenApi();
group.MapGet("/personal-data/{xtat}/decrypted", (string xTat, [SwaggerParameter("If provided, this user access token will be used over the internally stored one (that was restrieved via earlier 1206+1207 calls)")]string? userAccessToken) =>
{
Console.WriteLine("Retrieving decrypted personal data for xTAT: " + xTat);
return apimHelper.GetDecryptedPersonalData(xTat, userAccessToken);
})
.Produces<DecryptedPersonalData>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("GetDecryptedPersonalData")
.WithSummary("API 1202 - Get Personal Data AND decrypt response - First perform an OTP challenge using API 1206 and 1207 or explicitly provide user access token!")
.WithDescription("First perform an OTP challenge using API 1206 and 1207 or explicitly provide user access token!")
.WithOpenApi();
group.MapDelete("/personal-data/{xtat}", (string xTat, [SwaggerParameter("If provided, this user access token will be used over the internally stored one (that was restrieved via earlier 1206+1207 calls)")]string? userAccessToken) =>
{
Console.WriteLine("Deleting personal data for xTAT: " + xTat);
return apimHelper.DeletePersonalData(xTat, userAccessToken);
})
.Produces<DeletePersonalDataResponse>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("DeletePersonalData")
.WithSummary("API 1204 - Delete Personal Data - First perform an OTP challenge using API 1206 and 1207 or explicitly provide user access token!")
.WithDescription("First perform an OTP challenge using API 1206 and 1207 or explicitly provide user access token!")
.WithOpenApi();
group.MapPut("/personal-data/{xtat}", (string xTat, [SwaggerParameter("If provided, this user access token will be used over the internally stored one (that was restrieved via earlier 1206+1207 calls)")]string? userAccessToken, bool skipUpdateCounter, [SwaggerParameter("Should be at least two words (first name and last name)")]string? name, [SwaggerParameter("Should be a date between 1900-01-01 and now, in the format YYYY-MM-DD")]string? birthDate, [SwaggerSchema("Should be a JPG image, of max. 512KB and resolution between 520x520 and 720x720")]IFormFile? photo) =>
{
Console.WriteLine("Replacing personal data for xTAT: " + xTat);
return apimHelper.UpdatePersonalData(xTat, userAccessToken, skipUpdateCounter, name, birthDate, photo);
})
.WithName("UpdatePersonalData")
.WithSummary("API 1205 - Update Personal Data - First perform an OTP challenge using API 1206 and 1207 or explicitly provide user access token!")
.WithDescription("Performs a complete replacement; empty request parameters will result in the corresponding PADP attribute being deleted.")
.WithOpenApi();
group.MapGet("/v2/personal-data/{xtat}/generate-otp", (string xTat) =>
{
Console.WriteLine("Generating OTP for xTAT: " + xTat);
return apimHelper.GenerateOtpV2(xTat);
})
.Produces<OtpResponse>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("GenerateOtpV2")
.WithSummary("API 1206 V2 - Generate OTP")
.WithOpenApi();
group.MapGet("/v2/personal-data/{xtat}/validate-otp", (string xTat, string otp) =>
{
Console.WriteLine("Validating OTP {0} for xTAT: {1}", otp, xTat);
return apimHelper.ValidateOtpV2(xTat, otp);
})
.Produces<UserAccessToken>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("ValidateOtpV2")
.WithSummary("API 1207 V2 - Validate OTP")
.WithOpenApi();
group.MapGet("/v3/personal-data/generate-otp", (string? email, string? xTat) =>
{
if (email != null){
Console.WriteLine("Generating OTP for e-mail: " + email);
} else if (xTat != null){
Console.WriteLine("Generating OTP for xTAT: " + xTat);
}
return apimHelper.GenerateOtpV3(email, xTat);
})
.Produces<OtpResponse>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("GenerateOtpV3")
.WithSummary("API 1206 V3 - Generate OTP")
.WithDescription("If e-mail is provided, the OTP is generated for the e-mail address. If xTAT is provided, the OTP is generated for the xTAT.")
.WithOpenApi();
group.MapGet("/v3/personal-data/validate-otp", (string? email, string? xTat, string otp) =>
{
if (email != null){
Console.WriteLine("Validating OTP {0} for e-mail: {1}", otp, email);
} else if (xTat != null){
Console.WriteLine("Validating OTP {0} for xTAT: {1}", otp, xTat);
}
return apimHelper.ValidateOtpV3(email, xTat, otp);
})
.Produces<UserAccessToken>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("ValidateOtpV3")
.WithSummary("API 1207 V3 - Validate OTP")
.WithDescription("If e-mail is provided, the OTP is validated for the e-mail address. If xTAT is provided, the OTP is validated for the xTAT.")
.WithOpenApi();
group.MapGet("/personal-data/{xtat}/encrypted-update-init", (string xTat) =>
{
return apimHelper.CreateEphemeralKey(xTat);
})
.Produces<EphemeralKey>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("CreateEphemeralKey")
.WithSummary("API 1210 - Create Ephemeral Key")
.WithOpenApi();
group.MapGet("/personal-data/{xtat}/administrative-data", (string xTat) =>
{
Console.WriteLine("Retrieving administrative data for xTAT: {0}", xTat);
return apimHelper.GetAdministrativeData(xTat);
})
.Produces<AdministrativeData>(200)
.Produces<ErrorResponse>(400)
.Produces<ErrorResponse>(404)
.Produces<ErrorResponse>(500)
.WithName("GetAdministrativeData")
.WithSummary("API 1211 - Get Administrative Data")
.WithOpenApi();
pocGroup.MapGet("/encrypt-decrypt-poc", ([FromHeader]string textToEncrypt, string encryptedEphemeralKey) =>
{
Console.WriteLine("Text to encrypt: {0}", textToEncrypt);
return apimHelper.EncryptDecryptPoc(textToEncrypt, encryptedEphemeralKey);
})
.WithName("EncryptDecryptPoc")
.WithSummary("Encrypt/Decrypt POC")
.WithOpenApi();
pocGroup.MapGet("/encrypt-poc", ([FromHeader]string textToEncrypt, string encryptedEphemeralKey) =>
{
Console.WriteLine("Text to encrypt: {0}", textToEncrypt);
return apimHelper.EncryptPoc(textToEncrypt, encryptedEphemeralKey);
})
.WithName("EncryptPoc")
.WithSummary("Encrypt POC")
.WithOpenApi();
pocGroup.MapGet("/decrypt-poc", ([FromHeader]string textToDecrypt, string encryptedEphemeralKey) =>
{
Console.WriteLine("Text to decrypt: {0}", textToDecrypt);
return apimHelper.DecryptPoc(textToDecrypt, encryptedEphemeralKey);
})
.WithName("DecryptPoc")
.WithSummary("Decrypt POC")
.WithOpenApi();
app.Run();

View File

@ -0,0 +1,38 @@
// Rename this file to appsettings.json and provide correct credentials and locations for the cryptographic files
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"UserProperties": {
"uris": {
"apimBaseUri": "https://api-ovpay-acc.translink.nl",
"b2bApiUri": "/b2b-client-authentication/v1/token",
"padp1201Uri": "/pad-management/v2/personal-data/{xtat}",
"padp1202Uri": "/pad-management/v2/personal-data/{xtat}",
"padp1204Uri": "/pad-management/v2/personal-data/{xtat}",
"padp1205Uri": "/pad-management/v2/personal-data/{xtat}",
"padp1206V2Uri": "/pad-management/v2/personal-data/{xtat}/generate-otp",
"padp1207V2Uri": "/pad-management/v2/personal-data/{xtat}/validate-otp",
"padp1206V3Uri": "/pad-management/v3/personal-data/generate-otp",
"padp1207V3Uri": "/pad-management/v3/personal-data/validate-otp",
"padp1210Uri": "/pad-management/v2/personal-data/encrypted-update-init",
"padp1211Uri": "/pad-management/v2/personal-data/{xtat}/administrative-data"
},
"rsa": {
"publicKeyFile": "\\Properties\\{public key in PEM format}.pem",
"privateKeyFile": "\\Properties\\{private key in PEM format}.pem"
},
"credentials": {
"clientCertFile": "\\Properties\\{APIM client certificate}.pfx",
"clientCertPassword": "{pfxPassword}",
"clientId": "HTM_Retailer",
"clientSecret": "{clientSecret}",
"b2bApiKey": "{b2bApiKey}",
"padApiKey": "{padApiKey}"
}
}
}

View File

@ -0,0 +1,44 @@
using System.Text.Json.Serialization;
public class AdministrativeData
{
public AdministrativeData(AdministrativeDataElement name, AdministrativeDataElement photo, AdministrativeDataElement birthdate)
{
this.name = name;
this.photo = photo;
this.birthdate = birthdate;
}
public AdministrativeDataElement name { get; set; }
public AdministrativeDataElement photo { get; set; }
public AdministrativeDataElement birthdate { get; set; }
public class AdministrativeDataElement
{
public AdministrativeDataElement(bool inaccuracyFlag, string inaccuracyFlagReason, int inaccuracyFlagCounter, int changeCounter, int maxUpdatesVerificationCount, DateTime lastChangeDate, bool isValidated)
{
this.inaccuracyFlag = inaccuracyFlag;
this.inaccuracyFlagReason = inaccuracyFlagReason;
this.inaccuracyFlagCounter = inaccuracyFlagCounter;
this.changeCounter = changeCounter;
this.maxUpdatesVerificationCount = maxUpdatesVerificationCount;
this.lastChangeDate = lastChangeDate;
this.isValidated = isValidated;
}
[JsonPropertyName("inaccuracyFlag")]
public bool inaccuracyFlag { get; set; }
[JsonPropertyName("inaccuracyFlagReason")]
public string inaccuracyFlagReason { get; set; }
[JsonPropertyName("inaccuracyFlagCounter")]
public int inaccuracyFlagCounter { get; set; }
[JsonPropertyName("changeCounter")]
public int changeCounter { get; set; }
[JsonPropertyName("maxUpdatesVerificationCount")]
public int maxUpdatesVerificationCount { get; set; }
[JsonPropertyName("lastChangeDate")]
public DateTime lastChangeDate { get; set; }
[JsonPropertyName("isValidated")]
public bool isValidated { get; set; }
}
}

View File

@ -0,0 +1,33 @@
using System.Text.Json.Serialization;
public class B2bAccessToken
{
public B2bAccessToken(string accessToken, int expiresIn, int refreshExpiresIn, string refreshToken, string tokenType, int notBeforePolicy, string scope, string beId)
{
this.accessToken = accessToken;
this.expiresIn = expiresIn;
this.refreshExpiresIn = refreshExpiresIn;
this.refreshToken = refreshToken;
this.tokenType = tokenType;
this.notBeforePolicy = notBeforePolicy;
this.scope = scope;
this.beId = beId;
}
[JsonPropertyName("access_token")]
public string accessToken { get; set; }
[JsonPropertyName("expires_in")]
public int expiresIn { get; set; }
[JsonPropertyName("refresh_expires_in")]
public int refreshExpiresIn { get; set; }
[JsonPropertyName("refresh_token")]
public string refreshToken { get; set; }
[JsonPropertyName("token_type")]
public string tokenType { get; set; }
[JsonPropertyName("not-before-policy")]
public int notBeforePolicy { get; set; }
[JsonPropertyName("scope")]
public string scope { get; set; }
[JsonPropertyName("BE_ID")]
public string beId { get; set; }
}

View File

@ -0,0 +1,29 @@
using System.Text.Json.Serialization;
public class CreatePersonalDataRequest
{
[JsonPropertyName("metadata")]
public Metadata metadata { get; set; } = new Metadata();
[JsonPropertyName("data")]
public Data data { get; set; } = new Data();
public class Metadata
{
public string? email { get; set; }
public string? ephemeralKeyAlias { get; set; }
}
public class Data
{
public PersonalAccountData personalAccountData { get; set; } = new PersonalAccountData();
}
public class PersonalAccountData
{
public string? name { get; set; }
public string? birthdate { get; set; }
public string? photo { get; set; }
}
}

View File

@ -0,0 +1,23 @@
using System.Text.Json.Serialization;
using Swashbuckle.AspNetCore.Annotations;
public class DecryptedPersonalData
{
public DecryptedPersonalData(DecryptedData decryptedData, PersonalData encryptedData)
{
this.decryptedData = decryptedData;
this.encryptedData = encryptedData;
}
public DecryptedData decryptedData { get; set; }
public PersonalData encryptedData { get; set; }
public class DecryptedData
{
[JsonPropertyName("decryptedName")]
public string? decryptedName { get; set; }
[JsonPropertyName("decryptedBirthdate")]
public string? decryptedBirthdate { get; set; }
[SwaggerSchema(Format = "byte", Description = "Base64 encoded photo")]
public string? decryptedPhoto { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
public class DeletePersonalDataResponse
{
public DeletePersonalDataResponse(string[] deletedAttributes)
{
this.deletedAttributes = deletedAttributes;
}
[JsonPropertyName("deletedAttributes")]
public string[] deletedAttributes { get; set; }
}

View File

@ -0,0 +1,16 @@
using System.Text.Json.Serialization;
public class EphemeralKey
{
public EphemeralKey(string ephemeralKeyAlias, string encryptedEphemeralKey)
{
this.ephemeralKeyAlias = ephemeralKeyAlias;
this.encryptedEphemeralKey = encryptedEphemeralKey;
}
[JsonPropertyName("ephemeralKeyAlias")]
public string ephemeralKeyAlias { get; set; }
[JsonPropertyName("encryptedEphemeralKey")]
public string encryptedEphemeralKey { get; set; }
}

View File

@ -0,0 +1,38 @@
using System.Text.Json.Serialization;
public class ErrorResponse
{
[JsonConstructor]
public ErrorResponse(Error[] errors, string exceptionClassName, string exceptionStackTrace)
{
this.errors = errors;
this.exceptionClassName = exceptionClassName;
this.exceptionStackTrace = exceptionStackTrace;
}
public ErrorResponse(string errorMessage, int statusCode)
{
this.errors = new Error[] { new Error(statusCode.ToString(), new string[] { }, errorMessage) };
this.exceptionClassName = null;
this.exceptionStackTrace = null;
}
public Error[] errors { get; set; }
public string? exceptionClassName { get; set; }
public string? exceptionStackTrace { get; set; }
public class Error
{
public Error(string code, string[] data, string message)
{
this.code = code;
this.data = data;
this.message = message;
}
public string code { get; set; }
public string[] data { get; set; }
public string message { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System.Text.Json.Serialization;
public class GenerateOtpRequestV3
{
[JsonPropertyName("source")]
public string source { get; set; }
[JsonPropertyName("recipient")]
public string recipient { get; set; }
[JsonPropertyName("channel")]
public string channel { get; set; }
}

View File

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
public class OtpResponse
{
public OtpResponse(string maskedEmailAddress)
{
this.maskedEmailAddress = maskedEmailAddress;
}
[JsonPropertyName("maskedEmailAddress")]
public string maskedEmailAddress { get; set; }
}

View File

@ -0,0 +1,42 @@
using System.Reflection.Metadata.Ecma335;
using System.Text.Json.Serialization;
public class PersonalData
{
public PersonalData(Metadata metadata, Data data)
{
this.metadata = metadata;
this.data = data;
}
public Metadata metadata { get; set; }
public Data data { get; set; }
public class Metadata
{
public Metadata(string encryptedEphemeralKey)
{
this.encryptedEphemeralKey = encryptedEphemeralKey;
}
[JsonPropertyName("encryptedEphemeralKey")]
public string encryptedEphemeralKey { get; set; }
}
public class Data
{
public Data(string name, string birthdate, string photo)
{
this.name = name;
this.birthdate = birthdate;
this.photo = photo;
}
[JsonPropertyName("name")]
public string name { get; set; }
[JsonPropertyName("birthdate")]
public string birthdate { get; set; }
[JsonPropertyName("photo")]
public string photo { get; set; }
}
}

View File

@ -0,0 +1,42 @@
using System.Reflection;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
[AttributeUsage(
AttributeTargets.Class |
AttributeTargets.Struct |
AttributeTargets.Parameter |
AttributeTargets.Property |
AttributeTargets.Enum,
AllowMultiple = false)]
public class SwaggerSchemaExampleAttribute : Attribute
{
public SwaggerSchemaExampleAttribute(string example)
{
Example = example;
}
public string Example { get; set; }
}
public class SwaggerSchemaExampleFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (context.MemberInfo != null)
{
var schemaAttribute = context.MemberInfo.GetCustomAttributes<SwaggerSchemaExampleAttribute>()
.FirstOrDefault();
if (schemaAttribute != null)
ApplySchemaAttribute(schema, schemaAttribute);
}
}
private void ApplySchemaAttribute(OpenApiSchema schema, SwaggerSchemaExampleAttribute schemaAttribute)
{
if (schemaAttribute.Example != null)
{
schema.Example = new Microsoft.OpenApi.Any.OpenApiString(schemaAttribute.Example);
}
}
}

View File

@ -0,0 +1,29 @@
using System.Text.Json.Serialization;
public class UpdatePersonalDataRequest
{
[JsonPropertyName("metadata")]
public Metadata metadata { get; set; } = new Metadata();
[JsonPropertyName("data")]
public Data data { get; set; } = new Data();
public class Metadata
{
public bool skipUpdateCounter { get; set; }
public string? ephemeralKeyAlias { get; set; }
}
public class Data
{
public PersonalAccountData personalAccountData { get; set; } = new PersonalAccountData();
}
public class PersonalAccountData
{
public string? name { get; set; }
public string? birthdate { get; set; }
public string? photo { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
public class UserAccessToken
{
public UserAccessToken(string accessToken)
{
this.accessToken = accessToken;
}
[JsonPropertyName("accessToken")]
public string accessToken { get; set; }
}

View File

@ -0,0 +1,7 @@
public class UserAuthInfo
{
public string? UserAccessToken { get; set; }
public string? ephemeralKeyAlias { get; set; }
public string? encryptedEphemeralKey { get; set; }
}

View File

@ -0,0 +1,58 @@
public class UserProperties
{
public UserProperties(UrisSettings uris, RsaSettings rsa, CredentialsSettings credentials)
{
(Uris, Rsa, Credentials) = (uris, rsa, credentials);
}
public UrisSettings Uris { get; set; }
public RsaSettings Rsa { get; set; }
public CredentialsSettings Credentials { get; set; }
public class UrisSettings
{
public UrisSettings(string apimBaseUri, string b2bApiUri, string padp1201Uri, string padp1202Uri, string padp1204Uri, string padp1205Uri, string padp1206V2Uri, string padp1207V2Uri, string padp1206V3Uri, string padp1207V3Uri, string padp1210Uri, string padp1211Uri)
{
(ApimBaseUri, B2bApiUri, Padp1201Uri, Padp1202Uri, Padp1204Uri, Padp1205Uri, Padp1206V2Uri, Padp1207V2Uri, Padp1206V3Uri, Padp1207V3Uri, Padp1210Uri, Padp1211Uri) = (apimBaseUri, b2bApiUri, padp1201Uri, padp1202Uri, padp1204Uri, padp1205Uri, padp1206V2Uri, padp1207V2Uri, padp1206V3Uri, padp1207V3Uri, padp1210Uri, padp1211Uri);
}
public string ApimBaseUri { get; set; }
public string B2bApiUri { get; set; }
public string Padp1201Uri { get; set; }
public string Padp1202Uri { get; set; }
public string Padp1204Uri { get; set; }
public string Padp1205Uri { get; set; }
public string Padp1206V2Uri { get; set; }
public string Padp1207V2Uri { get; set; }
public string Padp1206V3Uri { get; set; }
public string Padp1207V3Uri { get; set; }
public string Padp1210Uri { get; set; }
public string Padp1211Uri { get; set; }
}
public class RsaSettings
{
public RsaSettings(string publicKeyFile, string privateKeyFile)
{
(PublicKeyFile, PrivateKeyFile) = (publicKeyFile, privateKeyFile);
}
public string PublicKeyFile { get; set; }
public string PrivateKeyFile { get; set; }
}
public class CredentialsSettings
{
public CredentialsSettings(string clientCertFile, string clientCertPassword, string clientId, string clientSecret, string b2bApiKey, string padApiKey)
{
(ClientCertFile, ClientCertPassword, ClientId, ClientSecret, B2bApiKey, PadApiKey) = (clientCertFile, clientCertPassword, clientId, clientSecret, b2bApiKey, padApiKey);
}
public string ClientCertFile { get; set; }
public string ClientCertPassword { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string B2bApiKey { get; set; }
public string PadApiKey { get; set; }
}
}

View File

@ -0,0 +1,13 @@
using System.Text.Json.Serialization;
public class ValidateOtpRequestV3
{
[JsonPropertyName("otp")]
public string otp { get; set; }
[JsonPropertyName("source")]
public string source { get; set; }
[JsonPropertyName("recipient")]
public string recipient { get; set; }
}

View File

@ -0,0 +1,38 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../../.." vcs="Git" />
</component>
</project>

View File

@ -0,0 +1,12 @@
# ABTProducts PUT request body generator
Simple tool to quickly edit HTM products via ABTProducts REST API.
- Requires JRE 21
- Run via: `java -jar ABTProductsPUTGenerator.jar`
- Specify custom input/output path via: `java -jar ABTProductsPUTGenerator.jar <inputPath> <outputPath>`
- Takes a ABTProducts GET response body in JSON format (product details)
- Generates the equivalent PUT request body - send via either:
- Postman WSO2 ABTProducts collection
- `curl -X PUT -H 'Content-Type: application/json' {baseUrl}/abt/abtproducts/1.0/38 --data @output.json`
- Default input path: /input.json
- Default output path: /output.json (output is overwritten if it exists)

View File

@ -0,0 +1,160 @@
{
"productId": 151,
"fikoArticleNumber": null,
"parentProductId": 114,
"gboPackageTemplateId": "33629",
"tapConnectProductCode": null,
"productName": "HTM Regio Vrij - Voltarief - Losse Maand - HL62",
"productDescription": "Voor een vast bedrag onbeperkt reizen met EBS, HTM en RET in gebied HL62",
"validityPeriod": {
"validityPeriodId": 262,
"fromInclusive": "2024-09-30T23:00:00.000+00:00",
"toInclusive": "2099-12-30T23:00:00.000+00:00"
},
"productTranslations": [
{
"language": "en",
"name": "HTM Regio Free - Full Fare - 1 Month - HL62",
"description": "For a fixed amount unlimited travel with EBS, HTM and RET in region HL62"
}
],
"productOwner": {
"productOwnerId": 19,
"name": "MRDH",
"organization": "MRDH"
},
"marketSegments": null,
"customerSegments": null,
"allowedGboAgeProfiles": [
{
"gboAgeProfileId": 1,
"name": "Baby/peuter (0 t/m 3 jaar)",
"ageFromInclusive": 0,
"ageToInclusive": 3
},
{
"gboAgeProfileId": 4,
"name": "Volwassene (19 t/m 64 jaar)",
"ageFromInclusive": 19,
"ageToInclusive": 64
},
{
"gboAgeProfileId": 5,
"name": "Oudere (65 jaar of ouder)",
"ageFromInclusive": 65,
"ageToInclusive": 999
}
],
"productCategory": {
"productCategoryId": 3,
"isTravelProduct": true,
"name": "Afgekocht reisrecht"
},
"requiredCustomerLevel": {
"requiredCustomerLevelId": 3,
"name": "profile"
},
"requiredProducts": null,
"incompatibleProducts": null,
"mandatoryCustomerDataItems": [
{
"mandatoryCustomerDataItemId": 1,
"customerDataItem": "birthname"
},
{
"mandatoryCustomerDataItemId": 2,
"customerDataItem": "surname"
},
{
"mandatoryCustomerDataItemId": 4,
"customerDataItem": "emailAddress"
},
{
"mandatoryCustomerDataItemId": 8,
"customerDataItem": "padBirthDate"
}
],
"requiredGboPersonalAttributes": [
{
"requiredGboPersonalAttributeId": 1,
"name": "NAME"
},
{
"requiredGboPersonalAttributeId": 2,
"name": "BIRTHDATE"
},
{
"requiredGboPersonalAttributeId": 3,
"name": "PHOTO"
}
],
"tokenTypes": [
{
"tokenTypeId": 1,
"name": "EMV"
}
],
"paymentMoment": {
"paymentMomentId": 1,
"name": "prepaid"
},
"serviceOptions": null,
"validityDuration": "P1M",
"maxStartInFutureDuration": "P6W",
"isRenewable": false,
"sendInvoice": false,
"imageReference": "https://web.acc.cloud.htm.nl/media/leif2leu/htm-logo-mobile.svg",
"productPageUrl": "https://web.acc.cloud.htm.nl/webshop/htm-regio-vrij",
"termsUrl": "https://web.acc.cloud.htm.nl/reisproducten/productvoorwaarden/htm-regio-vrij/",
"isSellableAtHtm": true,
"needsSolvencyCheckConsumer": false,
"needsSolvencyCheckBusiness": false,
"sellingPeriods": [
{
"sellingPeriodId": 214,
"fromInclusive": "2024-10-30T23:00:00.000+00:00",
"toInclusive": "2029-12-30T23:00:00.000+00:00",
"salesTouchpoint": {
"salesTouchpointId": 3,
"name": "Website (Perplex)",
"isActive": true,
"retailer": {
"retailerId": 1001,
"name": "HTM externe touchpoints",
"street": "Koningin Julianaplein",
"number": 10,
"numberAddition": null,
"postalCode": "2595 AA",
"city": "Den Haag",
"country": "Nederland",
"emailAddress": "info@htm.nl",
"phoneNumber": "070 374 9002",
"taxId": 572309345923,
"imageReference": "https://www.htm.nl/media/leif2leu/htm-logo-mobile.svg"
}
},
"forbiddenPaymentMethods": null,
"sellingPrices": [
{
"sellingPriceId": 195,
"taxCode": "V09",
"taxPercentage": 9.0000,
"amountExclTax": 13486,
"amountInclTax": 14700,
"fromInclusive": "2024-10-30T23:00:00.000+00:00",
"toInclusive": "2029-12-01T23:00:00.000+00:00",
"internalPrice": 0.0000
}
]
}
],
"purchasePrices": null,
"auditTrail": [
{
"auditTrailId": 475,
"action": "insert",
"user": "api",
"timestamp": "2025-05-07T14:05:43.213+00:00"
}
]
}

View File

@ -0,0 +1,59 @@
{
"fikoArticleNumber" : null,
"parentProductId" : 114,
"gboPackageTemplateId" : "33629",
"tapConnectProductCode" : null,
"productName" : "HTM Regio Vrij - Voltarief - Losse Maand - HL62",
"productDescription" : "Voor een vast bedrag onbeperkt reizen met EBS, HTM en RET in gebied HL62",
"validityPeriod" : {
"validityPeriodId" : 262,
"fromInclusive" : "2024-09-30T23:00:00.000+00:00",
"toInclusive" : "2099-12-30T23:00:00.000+00:00"
},
"productTranslations" : [ {
"language" : "en",
"name" : "HTM Regio Free - Full Fare - 1 Month - HL62",
"description" : "For a fixed amount unlimited travel with EBS, HTM and RET in region HL62"
} ],
"productOwnerId" : 19,
"marketSegmentIds" : null,
"customerSegmentIds" : null,
"allowedGboAgeProfileIds" : [ 1, 4, 5 ],
"productCategoryId" : 3,
"requiredCustomerLevelId" : 3,
"requiredProducts" : null,
"incompatibleProducts" : null,
"mandatoryCustomerDataItemIds" : [ 1, 2, 4, 8 ],
"requiredGboPersonalAttributeIds" : [ 1, 2, 3 ],
"tokenTypeIds" : [ 1 ],
"paymentMomentId" : 1,
"serviceOptionIds" : null,
"validityDuration" : "P1M",
"maxStartInFutureDuration" : "P6W",
"isRenewable" : false,
"sendInvoice" : false,
"imageReference" : "https://web.acc.cloud.htm.nl/media/leif2leu/htm-logo-mobile.svg",
"productPageUrl" : "https://web.acc.cloud.htm.nl/webshop/htm-regio-vrij",
"termsUrl" : "https://web.acc.cloud.htm.nl/reisproducten/productvoorwaarden/htm-regio-vrij/",
"isSellableAtHtm" : true,
"needsSolvencyCheckConsumer" : false,
"needsSolvencyCheckBusiness" : false,
"sellingPeriods" : [ {
"sellingPeriodId" : 214,
"fromInclusive" : "2024-10-30T23:00:00.000+00:00",
"toInclusive" : "2029-12-30T23:00:00.000+00:00",
"salesTouchpointId" : 3,
"forbiddenPaymentMethodIds" : null,
"sellingPrices" : [ {
"sellingPriceId" : 195,
"taxCode" : "V09",
"taxPercentage" : 9.0,
"amountExclTax" : 13486,
"amountInclTax" : 14700,
"fromInclusive" : "2024-10-30T23:00:00.000+00:00",
"toInclusive" : "2029-12-01T23:00:00.000+00:00",
"internalPrice" : 0.0
} ]
} ],
"purchasePrices" : null
}

View File

@ -0,0 +1,58 @@
{
"parentProductId" : null,
"productCode" : "30901-WA",
"gboPackageTemplateId" : "30901",
"tapConnectProductCode" : null,
"productGroupMetadata" : null,
"productName" : "HTM P1W Prolongatie-Test 90% Korting",
"productDescription" : "Reis je regelmatig met HTM? Activeer dan HTM 90% Korting op je betaalpas of credit card en reis met korting!",
"validityPeriod" : {
"validityPeriodId" : 148,
"fromInclusive" : "2023-12-31T23:00:00.000+00:00",
"toInclusive" : "2029-12-08T04:00:00.000+00:00"
},
"productTranslations" : [ {
"language" : "en",
"name" : "HTM Prolongation-Test 90% Discount",
"description" : "Are you a regular traveler? Activate HTM 90% discount on your EMV card!"
} ],
"productOwnerId" : 17,
"marketSegmentIds" : [ 1 ],
"customerSegmentIds" : [ 2, 3, 4, 5 ],
"productCategoryId" : 1,
"requiredCustomerLevelId" : 3,
"requiredProducts" : null,
"incompatibleProducts" : null,
"mandatoryCustomerDataItemIds" : [ 1, 2, 4, 5 ],
"requiredGboPersonalAttributes" : null,
"tokenTypeIds" : [ 1 ],
"paymentMomentId" : 1,
"serviceOptions" : null,
"validityDuration" : "P1W",
"maxStartInFutureDuration" : "P6W",
"isRenewable" : true,
"sendInvoice" : true,
"imageReference" : "https://web.acc.cloud.htm.nl/media/leif2leu/htm-logo-mobile.svg",
"productPageUrl" : "https://web.acc.cloud.htm.nl/webshop/htm-90-korting/",
"termsUrl" : "https://web.acc.cloud.htm.nl/reisproducten/productvoorwaarden/htm-90-korting/",
"isSellableAtHtm" : true,
"needsSolvencyCheckConsumer" : false,
"needsSolvencyCheckBusiness" : false,
"sellingPeriods" : [ {
"sellingPeriodId" : 89,
"fromInclusive" : "2024-09-30T23:00:00.000+00:00",
"toInclusive" : "2029-12-01T23:00:00.000+00:00",
"salesTouchpointId" : 3,
"forbiddenPaymentMethodIds" : null,
"sellingPrices" : [ {
"sellingPriceId" : 82,
"amountExclTax" : 92,
"amountInclTax" : 100,
"fromInclusive" : "2024-09-30T23:00:00.000+00:00",
"toInclusive" : "2029-12-01T23:00:00.000+00:00",
"internalPrice" : 0.0,
"taxMetadataId" : "47C8972E-A730-4032-9BDA-AF0A5BCB2C85"
} ]
} ],
"purchasePrices" : null
}

View File

@ -0,0 +1,67 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>nl.htm.ovpay.abt</groupId>
<artifactId>ABTProductsPUTGenerator</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ABTProductsPUTGenerator</name>
<description>Generate an ABTProducts PUT request body from a given ABTProducts GET response body</description>
<dependencies>
<!-- Log4j Slf4j Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.23.1</version>
</dependency>
<!-- JSON parsing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>nl.htm.ovpay.abt.ABTProductsPUTGenerator</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>21</source>
<target>21</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,338 @@
package nl.htm.ovpay.abt;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
public class ABTProductsPUTGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(ABTProductsPUTGenerator.class);
public static void main(String[] args) throws Exception {
if (args.length != 2) {
LOGGER.info("To modify input/output path, use: java -jar ABTProductsPUTGenerator.jar <inputPath> <outputPath>");
}
var inputFile = args.length > 0 ? args[0] : "input.json";
var outputFile = args.length > 1 ? args[1] : "output.json";
try (InputStream is = getInputStream(inputFile)) {
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(is);
Long productId = jsonNode.get("productId").asLong();
LOGGER.info("Successfully parsed product with productId {} from JSON:\n{}\n", productId, jsonNode.toPrettyString());
JsonNode putJsonNode = processJsonNode(jsonNode);
writeToFile(putJsonNode, outputFile);
LOGGER.info("DONE! Modify the output JSON as desired and send it as ABTProducts PUT request body:");
LOGGER.info("curl -X PUT -H 'Content-Type: application/json' {baseUrl}/abt/abtproducts/1.0/products/{} --data @{}", productId, outputFile);
}
}
private static InputStream getInputStream(String filePath) throws IOException {
var externalResource = new File(filePath);
if (externalResource.exists()) {
LOGGER.info("Loading ABTProducts details JSON from external file {}...", externalResource.getAbsolutePath());
return externalResource.toURI().toURL().openStream();
} else {
LOGGER.info("External file {} not found, using internal resource /input.json...", filePath);
return ABTProductsPUTGenerator.class.getResourceAsStream("/input.json");
}
}
private static void writeToFile(JsonNode jsonNode, String filePath) throws IOException {
ObjectMapper mapper = new ObjectMapper();
var outputFile = new File(filePath);
if (outputFile.exists()) {
LOGGER.info("Deleting existing output file {}...", filePath);
outputFile.delete();
}
mapper.writerWithDefaultPrettyPrinter().writeValue(outputFile, jsonNode);
LOGGER.info("Successfully wrote JSON to file {}!", outputFile.getAbsolutePath(), jsonNode.toPrettyString());
}
private static JsonNode processJsonNode(JsonNode jsonNode) {
var newJsonNode = new ObjectNode(new JsonNodeFactory(true));
jsonNode.fields().forEachRemaining(jsonField -> {
if (!List.of(JsonNodeType.ARRAY, JsonNodeType.OBJECT).contains(jsonField.getValue().getNodeType())) {
if (jsonField.getValue().isNull()) {
checkRewriteNullFields(jsonField, newJsonNode);
} else if (!jsonField.getKey().equals("productId") && !jsonField.getKey().equals("auditTrail")) {
LOGGER.info("Keeping {} as-is...", jsonField.getKey());
newJsonNode.put(jsonField.getKey(), jsonField.getValue());
}
} else {
if (List.of("validityPeriod", "productTranslations").contains(jsonField.getKey())) {
LOGGER.info("Keeping {} as-is...", jsonField.getKey());
newJsonNode.set(jsonField.getKey(), jsonField.getValue());
} else {
rewriteObjectFields(jsonField, newJsonNode);
rewriteArrayFields(jsonField, newJsonNode);
}
}
});
LOGGER.info("Successfully rewritten into PUT JSON:\n{}\n", newJsonNode.toPrettyString());
return newJsonNode;
}
private static void checkRewriteNullFields(Map.Entry<String, JsonNode> jsonField, JsonNode newJsonNode) {
switch (jsonField.getKey()) {
case "productOwner" -> {
LOGGER.info("Rewriting null productOwner to productOwnerId...");
((ObjectNode)newJsonNode).putRawValue("productOwnerId", null);
}
case "productCategory" -> {
LOGGER.info("Rewriting null productCategory to productCategoryId...");
((ObjectNode)newJsonNode).putRawValue("productCategoryId", null);
}
case "paymentMoment" -> {
LOGGER.info("Rewriting null paymentMoment to paymentMomentId...");
((ObjectNode)newJsonNode).putRawValue("paymentMomentId", null);
}
case "requiredCustomerLevel" -> {
LOGGER.info("Rewriting null requiredCustomerLevel to requiredCustomerLevelId...");
((ObjectNode)newJsonNode).putRawValue("requiredCustomerLevelId", null);
}
case "layerInfo" -> {
LOGGER.info("Rewriting null layerInfo to layerInfoId...");
((ObjectNode)newJsonNode).putRawValue("layerInfoId", null);
}
case "marketSegments" -> {
LOGGER.info("Rewriting null marketSegments to marketSegmentIds...");
((ObjectNode)newJsonNode).putRawValue("marketSegmentIds", null);
}
case "customerSegments" -> {
LOGGER.info("Rewriting null customerSegments to customerSegmentIds...");
((ObjectNode)newJsonNode).putRawValue("customerSegmentIds", null);
}
case "allowedGboAgeProfiles" -> {
LOGGER.info("Rewriting null allowedGboAgeProfiles to allowedGboAgeProfileIds...");
((ObjectNode)newJsonNode).putRawValue("allowedGboAgeProfileIds", null);
}
case "mandatoryCustomerDataItems" -> {
LOGGER.info("Rewriting null mandatoryCustomerDataItems to mandatoryCustomerDataItemIds...");
((ObjectNode)newJsonNode).putRawValue("mandatoryCustomerDataItemIds", null);
}
case "requiredGboPersonalAttributes" -> {
LOGGER.info("Rewriting null requiredGboPersonalAttributes to requiredGboPersonalAttributeIds...");
((ObjectNode)newJsonNode).putRawValue("requiredGboPersonalAttributeIds", null);
}
case "tokenTypes" -> {
LOGGER.info("Rewriting null tokenTypes to tokenTypeIds...");
((ObjectNode)newJsonNode).putRawValue("tokenTypeIds", null);
}
case "serviceOptions" -> {
LOGGER.info("Rewriting null serviceOptions to serviceOptionIds...");
((ObjectNode)newJsonNode).putRawValue("serviceOptionIds", null);
}
default -> {
LOGGER.info("Keeping {} as-is...", jsonField.getKey());
((ObjectNode)newJsonNode).put(jsonField.getKey(), jsonField.getValue());
}
}
}
private static void rewriteObjectFields(Map.Entry<String, JsonNode> jsonField, JsonNode newJsonNode) {
switch (jsonField.getKey()) {
case "productOwner" -> {
LOGGER.info("Rewriting productOwner to productOwnerId...");
Long productOwnerId = jsonField.getValue().get("productOwnerId").asLong();
((ObjectNode)newJsonNode).put("productOwnerId", productOwnerId);
}
case "productCategory" -> {
LOGGER.info("Rewriting productCategory to productCategoryId...");
Long productCategoryId = jsonField.getValue().get("productCategoryId").asLong();
((ObjectNode)newJsonNode).put("productCategoryId", productCategoryId);
}
case "paymentMoment" -> {
LOGGER.info("Rewriting paymentMoment to paymentMomentId...");
Long paymentMomentId = jsonField.getValue().get("paymentMomentId").asLong();
((ObjectNode)newJsonNode).put("paymentMomentId", paymentMomentId);
}
case "requiredCustomerLevel" -> {
LOGGER.info("Rewriting requiredCustomerLevel to requiredCustomerLevelId...");
Long requiredCustomerLevelId = jsonField.getValue().get("requiredCustomerLevelId").asLong();
((ObjectNode)newJsonNode).put("requiredCustomerLevelId", requiredCustomerLevelId);
}
case "layerInfo" -> {
LOGGER.info("Rewriting layerInfo to layerInfoId...");
Long layerInfoId = jsonField.getValue().get("layerInfoId").asLong();
((ObjectNode)newJsonNode).put("layerInfoId", layerInfoId);
}
}
}
private static void rewriteArrayFields(Map.Entry<String, JsonNode> jsonField, JsonNode newJsonNode) {
switch (jsonField.getKey()) {
case "marketSegments" -> {
LOGGER.info("Rewriting marketSegments to marketSegmentIds...");
if (jsonField.getValue() != null) {
ArrayNode marketSegmentIds = new ArrayNode(new JsonNodeFactory(true));
((ArrayNode)jsonField.getValue()).elements().forEachRemaining(marketSegment -> {
marketSegmentIds.add(marketSegment.get("marketSegmentId").asLong());
});
((ObjectNode)newJsonNode).putArray("marketSegmentIds").addAll(marketSegmentIds);
} else {
((ObjectNode)newJsonNode).putRawValue("marketSegmentIds", null);
}
}
case "customerSegments" -> {
LOGGER.info("Rewriting customerSegments to customerSegmentIds...");
if (jsonField.getValue() != null) {
ArrayNode customerSegmentIds = new ArrayNode(new JsonNodeFactory(true));
((ArrayNode)jsonField.getValue()).elements().forEachRemaining(customerSegment -> {
customerSegmentIds.add(customerSegment.get("customerSegmentId").asLong());
});
((ObjectNode)newJsonNode).putArray("customerSegmentIds").addAll(customerSegmentIds);
} else {
((ObjectNode)newJsonNode).putRawValue("customerSegmentIds", null);
}
}
case "allowedGboAgeProfiles" -> {
LOGGER.info("Rewriting allowedGboAgeProfiles to allowedGboAgeProfileIds...");
if (jsonField.getValue() != null) {
ArrayNode allowedGboAgeProfileIds = new ArrayNode(new JsonNodeFactory(true));
((ArrayNode)jsonField.getValue()).elements().forEachRemaining(allowedGboAgeProfile -> {
allowedGboAgeProfileIds.add(allowedGboAgeProfile.get("gboAgeProfileId").asLong());
});
((ObjectNode)newJsonNode).putArray("allowedGboAgeProfileIds").addAll(allowedGboAgeProfileIds);
} else {
((ObjectNode)newJsonNode).putRawValue("allowedGboAgeProfileIds", null);
}
}
case "tokenTypes" -> {
LOGGER.info("Rewriting tokenTypes to tokenTypeIds...");
if (jsonField.getValue() != null) {
ArrayNode tokenTypeIds = new ArrayNode(new JsonNodeFactory(true));
((ArrayNode)jsonField.getValue()).elements().forEachRemaining(tokenType -> {
tokenTypeIds.add(tokenType.get("tokenTypeId").asLong());
});
((ObjectNode)newJsonNode).putArray("tokenTypeIds").addAll(tokenTypeIds);
} else {
((ObjectNode)newJsonNode).putRawValue("tokenTypeIds", null);
}
}
case "mandatoryCustomerDataItems" -> {
LOGGER.info("Rewriting mandatoryCustomerDataItems to mandatoryCustomerDataItemIds...");
if (jsonField.getValue() != null) {
ArrayNode mandatoryCustomerDataItemIds = new ArrayNode(new JsonNodeFactory(true));
((ArrayNode)jsonField.getValue()).elements().forEachRemaining(mandatoryCustomerDataItem -> {
mandatoryCustomerDataItemIds.add(mandatoryCustomerDataItem.get("mandatoryCustomerDataItemId").asLong());
});
((ObjectNode)newJsonNode).putArray("mandatoryCustomerDataItemIds").addAll(mandatoryCustomerDataItemIds);
} else {
((ObjectNode)newJsonNode).putRawValue("mandatoryCustomerDataItemIds", null);
}
}
case "requiredGboPersonalAttributes" -> {
LOGGER.info("Rewriting requiredGboPersonalAttributes to requiredGboPersonalAttributeIds...");
if (jsonField.getValue() != null) {
ArrayNode requiredGboPersonalAttributeIds = new ArrayNode(new JsonNodeFactory(true));
((ArrayNode)jsonField.getValue()).elements().forEachRemaining(requiredGboPersonalAttribute -> {
requiredGboPersonalAttributeIds.add(
requiredGboPersonalAttribute.get("requiredGboPersonalAttributeId").asLong());
});
((ObjectNode)newJsonNode).putArray("requiredGboPersonalAttributeIds").addAll(requiredGboPersonalAttributeIds);
} else {
((ObjectNode)newJsonNode).putRawValue("requiredGboPersonalAttributeIds", null);
}
}
case "serviceOptions" -> {
LOGGER.info("Rewriting serviceOptions to serviceOptionIds...");
if (jsonField.getValue() != null) {
ArrayNode serviceOptionIds = new ArrayNode(new JsonNodeFactory(true));
((ArrayNode)jsonField.getValue()).elements().forEachRemaining(serviceOption -> {
serviceOptionIds.add(serviceOption.get("serviceOptionId").asLong());
});
((ObjectNode)newJsonNode).putArray("serviceOptionIds").addAll(serviceOptionIds);
} else {
((ObjectNode)newJsonNode).putRawValue("serviceOptionIds", null);
}
}
case "incompatibleProducts" -> {
LOGGER.info("Rewriting incompatibleProducts to remove product names...");
if (jsonField.getValue() != null) {
ArrayNode incompatibleProducts = ((ArrayNode)jsonField.getValue()).deepCopy();
incompatibleProducts.elements().forEachRemaining(incompatibleProduct -> {
((ObjectNode)incompatibleProduct).remove("productName");
});
((ObjectNode)newJsonNode).putArray("incompatibleProducts").addAll(incompatibleProducts);
} else {
((ObjectNode)newJsonNode).putRawValue("incompatibleProducts", null);
}
}
case "requiredProducts" -> {
LOGGER.info("Rewriting requiredProducts to remove product names...");
if (jsonField.getValue() != null) {
ArrayNode requiredProducts = ((ArrayNode)jsonField.getValue()).deepCopy();
requiredProducts.elements().forEachRemaining(requiredProduct -> {
((ObjectNode)requiredProduct).remove("productName");
});
((ObjectNode)newJsonNode).putArray("requiredProducts").addAll(requiredProducts);
} else {
((ObjectNode)newJsonNode).putRawValue("requiredProducts", null);
}
}
case "sellingPeriods" -> {
if (jsonField.getValue() != null) {
LOGGER.info("Rewriting salesTouchpoint in sellingPeriods to salesTouchpointId...");
ArrayNode sellingPeriods = ((ArrayNode)jsonField.getValue()).deepCopy();
sellingPeriods.elements().forEachRemaining(sellingPeriod -> {
Long salesTouchpointId = sellingPeriod.get("salesTouchpoint").get("salesTouchpointId").asLong();
((ObjectNode)sellingPeriod).put("salesTouchpointId", salesTouchpointId);
((ObjectNode)sellingPeriod).remove("salesTouchpoint");
if (sellingPeriod.get("forbiddenPaymentMethods") != null) {
LOGGER.info("Rewriting forbiddenPaymentMethods to forbiddenPaymentMethodIds...");
ArrayNode forbiddenPaymentMethodIds = new ArrayNode(new JsonNodeFactory(true));
sellingPeriod.get("forbiddenPaymentMethods").elements().forEachRemaining(forbiddenPaymentMethod -> {
forbiddenPaymentMethodIds.add(forbiddenPaymentMethod.get("forbiddenPaymentMethodId").asLong());
});
((ObjectNode)sellingPeriod).remove("forbiddenPaymentMethods");
if (!forbiddenPaymentMethodIds.isEmpty()) {
((ObjectNode)sellingPeriod).putArray("forbiddenPaymentMethodIds").addAll(forbiddenPaymentMethodIds);
} else {
((ObjectNode)sellingPeriod).putRawValue("forbiddenPaymentMethodIds", null);
}
}
if (!sellingPeriod.get("sellingPrices").isNull()) {
LOGGER.info("Deep-copying sellingPrices...");
ArrayNode sellingPrices = ((ArrayNode)sellingPeriod.get("sellingPrices")).deepCopy();
((ObjectNode)sellingPeriod).remove("sellingPrices");
if (!sellingPrices.isEmpty()) {
((ObjectNode)sellingPeriod).putArray("sellingPrices").addAll(sellingPrices);
} else {
((ObjectNode)sellingPeriod).putRawValue("sellingPrices", null);
}
}
});
((ObjectNode)newJsonNode).putArray("sellingPeriods").addAll(sellingPeriods);
} else {
((ObjectNode)newJsonNode).putRawValue("sellingPeriods", null);
}
}
case "purchasePrices" -> {
LOGGER.info("Deep-copying purchasePrices...");
if (!jsonField.getValue().isNull()) {
ArrayNode purchasePrices = ((ArrayNode)jsonField.getValue()).deepCopy();
((ObjectNode)newJsonNode).putArray("purchasePrices").addAll(purchasePrices);
} else {
((ObjectNode)newJsonNode).putRawValue("purchasePrices", null);
}
}
}
}
}

View File

@ -0,0 +1,202 @@
{
"productId": 251,
"fikoArticleNumber": null,
"parentProductId": null,
"gboPackageTemplateId": "30901",
"tapConnectProductCode": null,
"productName": "MaxTestPOST-21-okt-test-1 edited PUT",
"productDescription": "21-okt-test-1 edited PUT - reis met 90% korting gedurende de eerste F&F pilot!",
"validityPeriod": null,
"productTranslations": null,
"productOwner": {
"productOwnerId": 1,
"name": "Corneel Verstoep",
"organization": "HTM"
},
"marketSegments": null,
"customerSegments": null,
"allowedGboAgeProfiles": null,
"productCategory": {
"productCategoryId": 9,
"isTravelProduct": true,
"name": "Kortingsabonnement"
},
"requiredCustomerLevel": {
"requiredCustomerLevelId": 1,
"name": "guest"
},
"requiredProducts": null,
"incompatibleProducts": null,
"mandatoryCustomerDataItems": [
{
"mandatoryCustomerDataItemId": 4,
"customerDataItem": "emailAddress"
},
{
"mandatoryCustomerDataItemId": 5,
"customerDataItem": "address"
}
],
"requiredGboPersonalAttributes": [
{
"requiredGboPersonalAttributeId": 1,
"name": "NAME"
},
{
"requiredGboPersonalAttributeId": 2,
"name": "BIRTHDATE"
},
{
"requiredGboPersonalAttributeId": 3,
"name": "PHOTO"
}
],
"tokenTypes": [
{
"tokenTypeId": 1,
"name": "EMV"
}
],
"paymentMoment": {
"paymentMomentId": 1,
"name": "prepaid"
},
"serviceOptions": null,
"validityDuration": "P7D",
"maxStartInFutureDuration": "P6W",
"isRenewable": false,
"sendInvoice": false,
"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/nog-onbekende-productvoorwaarden-pagina",
"isSellableAtHtm": true,
"needsSolvencyCheckConsumer": false,
"needsSolvencyCheckBusiness": false,
"sellingPeriods": [
{
"sellingPeriodId": 240,
"fromInclusive": "2024-09-06T00:00:00.000+00:00",
"toInclusive": "2024-12-29T23:59:59.000+00:00",
"salesTouchpoint": {
"salesTouchpointId": 6,
"name": "Service-engine",
"isActive": true,
"retailer": {
"retailerId": 1000,
"name": "HTM intern beheer",
"street": "Koningin Julianaplein",
"number": 10,
"numberAddition": null,
"postalCode": "2595 AA",
"city": "Den Haag",
"country": "Nederland",
"emailAddress": "info@htm.nl",
"phoneNumber": "070 374 9002",
"taxId": null,
"imageReference": "https://www.htm.nl/typo3conf/ext/htm_template/Resources/Public/img/logo.svg"
}
},
"forbiddenPaymentMethods": null,
"sellingPrices": [
{
"sellingPriceId": 318,
"taxCode": "V21",
"taxPercentage": 21.0000,
"amountExclTax": 94,
"amountInclTax": 100,
"fromInclusive": "2024-09-06T00:00:00.000+00:00",
"toInclusive": "2024-12-18T23:59:59.000+00:00",
"internalPrice": 92.0000
},
{
"sellingPriceId": 319,
"taxCode": "V21",
"taxPercentage": 21.0000,
"amountExclTax": 98,
"amountInclTax": 102,
"fromInclusive": "2024-12-19T00:00:00.000+00:00",
"toInclusive": "2024-12-29T23:59:59.000+00:00",
"internalPrice": 0.0000
}
]
},
{
"sellingPeriodId": 241,
"fromInclusive": "2024-09-06T00:00:00.000+00:00",
"toInclusive": "2024-12-29T23:59:59.000+00:00",
"salesTouchpoint": {
"salesTouchpointId": 5,
"name": "Servicewinkel (Team Incident Masters)",
"isActive": true,
"retailer": {
"retailerId": 1001,
"name": "HTM externe touchpoints",
"street": "Koningin Julianaplein",
"number": 10,
"numberAddition": null,
"postalCode": "2595 AA",
"city": "Den Haag",
"country": "Nederland",
"emailAddress": "info@htm.nl",
"phoneNumber": "070 374 9002",
"taxId": null,
"imageReference": "https://www.htm.nl/typo3conf/ext/htm_template/Resources/Public/img/logo.svg"
}
},
"forbiddenPaymentMethods": [
{
"forbiddenPaymentMethodId": 2,
"name": "creditcard",
"issuer": "Visa"
}
],
"sellingPrices": [
{
"sellingPriceId": 320,
"taxCode": "V21",
"taxPercentage": 21.0000,
"amountExclTax": 94,
"amountInclTax": 100,
"fromInclusive": "2024-09-06T00:00:00.000+00:00",
"toInclusive": "2024-12-18T23:59:59.000+00:00",
"internalPrice": 92.0000
},
{
"sellingPriceId": 321,
"taxCode": "V21",
"taxPercentage": 21.0000,
"amountExclTax": 98,
"amountInclTax": 102,
"fromInclusive": "2024-12-19T00:00:00.000+00:00",
"toInclusive": "2024-12-29T23:59:59.000+00:00",
"internalPrice": 0.0000
}
]
}
],
"purchasePrices": [
{
"purchasePriceId": 184,
"taxCode": "V21",
"taxPercentage": 21.0000,
"amountExclTax": 0,
"amountInclTax": 0,
"fromInclusive": "2024-09-01T00:00:00.000+00:00",
"toInclusive": "2024-12-31T23:59:59.000+00:00"
}
],
"auditTrail": [
{
"auditTrailId": 228,
"action": "update",
"user": "api",
"timestamp": "2024-10-21T09:00:30.410+00:00"
},
{
"auditTrailId": 227,
"action": "insert",
"user": "api",
"timestamp": "2024-10-21T08:58:39.237+00:00"
}
]
}

View File

@ -0,0 +1,17 @@
<Configuration status="INFO">
<Appenders>
<Console name="STDOUT-COLOR">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} | %highlight{%-5level} | %cyan{%-28c{1}} - %msg %blue{[%t]}%n"
disableAnsi="false"/>
</Console>
<Console name="STDOUT-NOCOLOR">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %-28c{1} - %msg [%t]%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="STDOUT-NOCOLOR"/>
</Root>
</Loggers>
</Configuration>

41
src/java/rabbitmq-poc/.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### IntelliJ IDEA ###
.idea
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store
/logs

View File

@ -0,0 +1,49 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>nl.ovpay</groupId>
<artifactId>rabbitmq</artifactId>
<version>1.0-SNAPSHOT</version>
<name>OVpay - RabbitMQ POC</name>
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.23.0</version>
</dependency>
<!-- Log4j Slf4j Logging -->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.23.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20240303</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,40 @@
package nl.ovpay.queue;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public final class DummyX509TrustManager implements X509TrustManager {
private static DummyX509TrustManager INSTANCE;
private DummyX509TrustManager() {
// prevent instantiation
}
public static DummyX509TrustManager getInstance() {
if (INSTANCE == null) {
INSTANCE = new DummyX509TrustManager();
}
return INSTANCE;
}
public static TrustManager[] getDummyArray() {
if (INSTANCE == null) {
INSTANCE = new DummyX509TrustManager();
}
return new TrustManager[] { INSTANCE };
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}

View File

@ -0,0 +1,113 @@
package nl.ovpay.queue;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class Helpers {
private static Logger LOGGER = LoggerFactory.getLogger(Helpers.class);
public static String getAlertId(String string) throws IOException {
return new JSONObject(string).get("alertId").toString();
}
public static String getTripId(String string) throws IOException {
return new JSONObject(string).get("tripId").toString();
}
public static String getXbot(String string) throws IOException {
return new JSONObject(string).get("xbot").toString();
}
public static void getTripDetails(String tripId, String xbot, String gboBearerToken) throws Exception {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, DummyX509TrustManager.getDummyArray(), new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://api.sbx.idbt.translink.nl/api/v3/id-media/tokens/xbot/" + xbot + "/trips/details/" + tripId);
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection)con;
http.setRequestMethod("GET");
http.setDoOutput(true);
http.setRequestProperty("Authorization", "Bearer " + gboBearerToken);
http.connect();
try(InputStream is = http.getInputStream()) {
String response = new String(is.readAllBytes(), StandardCharsets.UTF_8);
LOGGER.info("GBO API 8659 trip details response for xBOT " + xbot + " and tripId " + tripId + ": \n" + new JSONObject(response).toString(2));
}
}
public static void getAlertDetails(String alertId, String xBot, String gboBearerToken) throws Exception {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, DummyX509TrustManager.getDummyArray(), new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://api.sbx.idbt.translink.nl/api/v3/id-media/tokens/xbot/" + xBot + "/alerts/" + alertId + "/details");
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection)con;
http.setRequestMethod("GET");
http.setDoOutput(true);
http.setRequestProperty("Authorization", "Bearer " + gboBearerToken);
http.connect();
try(InputStream is = http.getInputStream()) {
String response = new String(is.readAllBytes(), StandardCharsets.UTF_8);
LOGGER.info("GBO API 8851 alert details response for xBOT " + xBot + " and alertId " + alertId + ": \n" + new JSONObject(response).toString(2));
}
}
public static String getGboBearerToken() throws IOException, NoSuchAlgorithmException, KeyManagementException {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, DummyX509TrustManager.getDummyArray(), new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
URL url = new URL("https://api.sbx.idbt.translink.nl/api/v3/auth/oauth2/token");
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection)con;
http.setRequestMethod("POST");
http.setDoOutput(true);
Map<String,String> arguments = new HashMap<>();
arguments.put("client_id", "HTM-auth-client");
arguments.put("client_secret", "HTM-auth-827kJJ");
arguments.put("grant_type", "client_credentials");
StringJoiner sj = new StringJoiner("&");
for(Map.Entry<String,String> entry : arguments.entrySet())
sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "="
+ URLEncoder.encode(entry.getValue(), "UTF-8"));
byte[] out = sj.toString().getBytes(StandardCharsets.UTF_8);
int length = out.length;
http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.connect();
try(OutputStream os = http.getOutputStream()) {
os.write(out);
}
try(InputStream is = http.getInputStream()) {
String response = new String(is.readAllBytes(), StandardCharsets.UTF_8);
JSONObject json = new JSONObject(response);
LOGGER.info("Got GBO bearer token: " + json.get("access_token"));
return json.get("access_token").toString();
}
}
}

View File

@ -0,0 +1,104 @@
package nl.ovpay.queue;
import java.util.Map;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
import com.rabbitmq.client.impl.ForgivingExceptionHandler;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RabbitConnector {
private static final Logger LOGGER = LoggerFactory.getLogger(RabbitConnector.class);
// TRIPS
// SubscriptionId = 3e246de5-d3ad-468f-834b-1aaebf52244c
// Use API 9853 to manually add xBOT to queue
private static final String QUEUE_NAME = "BEID_3.TRIPS";
private static final String USER_NAME = "BEID_3_TRIPS_HlTT";
private static final String PASSWORD = "xJR4C8hIqhHQw0sn";
// ALERTS
// SubscriptionId = 17c8100b-88a2-4cef-b40d-8dca4f93d311
// Use API 9853 to manually add xBOT to queue
// private static final String QUEUE_NAME = "BEID_3.ALERTS";
// private static final String USER_NAME = "BEID_3_ALERTS_nZs3";
// private static final String PASSWORD = "VyubhPnczKgTB2zJ";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setVirtualHost("/");
factory.setAutomaticRecoveryEnabled(true);
factory.setPort(443);
factory.setHost("not.sbx.idbt.translink.nl");
factory.setUsername(USER_NAME);
factory.setPassword(PASSWORD);
factory.useSslProtocol("TLSv1.2");
factory.setExceptionHandler(new ForgivingExceptionHandler());
Map<String, Object> configs = factory.getClientProperties();
LOGGER.info("Client properties: \n" + new JSONObject(configs).toString(2));
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
DeliverCallback deliverCallback = initDeliverCallback(channel);
AMQP.Queue.DeclareOk queue = channel.queueDeclarePassive(QUEUE_NAME);
LOGGER.info(
"Declared queue: " + queue.getQueue() + ", consumer count: " + queue.getConsumerCount() + ", message count: " +
queue.getMessageCount());
// Second parameter controls autoAck - false = no autoAck = messages are only deleted from queue after consumer acknowledges them
channel.basicConsume(queue.getQueue(), false, deliverCallback, consumerTag -> {});
LOGGER.info("Waiting for messages from the queue. To exit press CTRL+C");
}
private static DeliverCallback initDeliverCallback(Channel channel) {
return (consumerTag, delivery) -> {
final String message = new String(delivery.getBody(), "UTF-8");
LOGGER.info("Received from message from the queue: \n " + new JSONObject(message).toString(2));
LOGGER.info("Acknowledging message with delivery tag: " + delivery.getEnvelope().getDeliveryTag());
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
LOGGER.info("Successfully acknowledged message with delivery tag: " + delivery.getEnvelope().getDeliveryTag());
if (QUEUE_NAME.equals("BEID_3.TRIPS")) {
getTripDetails(message);
} else if (QUEUE_NAME.equals("BEID_3.ALERTS")) {
getAlertDetails(message);
}
};
}
private static void getAlertDetails(String message) {
try {
String alertId = Helpers.getAlertId(message);
String xBot = Helpers.getXbot(message);
String gboBearerToken = Helpers.getGboBearerToken();
LOGGER.info("Getting alert details for xBOT {} and alertId {} via GBO API 8851...", xBot, alertId);
Helpers.getAlertDetails(alertId, xBot, gboBearerToken);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void getTripDetails(String message) {
try {
String tripId = Helpers.getTripId(message);
String xBot = Helpers.getXbot(message);
String gboBearerToken = Helpers.getGboBearerToken();
LOGGER.info("Getting trip details for xBOT {} and tripId {} via GBO API 8659...", xBot, tripId);
Helpers.getTripDetails(tripId, xBot, gboBearerToken);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,27 @@
<Configuration status="INFO">
<Appenders>
<Console name="STDOUT-COLOR">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} | %highlight{%-5level} | %cyan{%-28c{1}} - %msg %blue{[%t]}%n"
disableAnsi="false"/>
</Console>
<Console name="STDOUT-NOCOLOR">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %-28c{1} - %msg [%t]%n"/>
</Console>
<RollingFile name="FILE-NOCOLOR"
fileName="logs/rabbitmq-poc.log"
filePattern="logs/rabbitmq-poc.log.%i.gz">
<DefaultRolloverStrategy max="100"/>
<Policies>
<SizeBasedTriggeringPolicy size="1M"/>
</Policies>
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} | %-5level | %-28c{1} - %msg [%t]%n"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO">
<AppenderRef ref="STDOUT-COLOR"/>
<AppenderRef ref="FILE-NOCOLOR"/>
</Root>
</Loggers>
</Configuration>

View File

@ -0,0 +1,482 @@
openapi: 3.0.1
info:
title: Personal Account Data (PAD) APIs for touchpoints and Service Engine
description: |-
APIs for touchpoints and Service Engine to manage Personal Account Data (PAD) on OVpay tokens (xTATs).\
These APIs connect directly to the PADP APIs in GBO APIM and are implemented in Logic Apps
in the Integration Layer.
version: '1.0'
servers:
- url: https://api.integratielaag.nl/abt/touchpoint/1.0
tags:
- name: Personal Data APIs for touchpoints
description: Personal Data APIs for touchpoints, no Service Engine in between!
- name: Personal Data APIs for Service Engine
description: Personal Data APIs for Service Engine, not to be exposed to touchpoints!
paths:
/personal-data/{xtat}:
post:
tags:
- Personal Data APIs for touchpoints
summary: Add the supplied Personal Data to the given xTAT (that should not contain any Personal Data yet).
description: |-
- The given xTAT should not contain any Personal Data yet (the PATCH endpoint should be used in that case) - if the given xTAT already contains Personal Data, an error is thrown;
- The given e-mail address will be used for future OTP challenges to manage the Personal Data in the future - this e-mail adress should therefore be validated;
- If the e-mail address is not yet validated by other means (e.g. the e-mail address is used for login, or is entered twice to prevent typos), an OTP challenge for the e-mail address should be triggered and supplied to this endpoint;
- xTAT and e-mail address are always required, for the Personal Data it is allowed to supply any subset, or all three data attributes;
- Each of the three data attributes is validated - for the requirements per attribute, see the descriptions in the request details below;
- If any attribute fails validation, none of the attributes will be added to the xTAT.
operationId: CreatePersonalData
parameters:
- name: xtat
in: path
required: true
example: 'c3a6c0f2-3b6a-4b9a-9c5d-5d9c6b3a4c5d'
schema:
type: string
format: uuid
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- email
properties:
email:
type: string
format: email
description: Email address to be used for OTP challenges to prove ownership and manage the Personal Data in the future
example: 8Z9dG@example.com
otp:
type: string
pattern: ^[0-9]{6}$
description: OTP is optional, should be supplied if the e-mail address is not yet validated by other means (e.g. the e-mail address is used for login, or is entered twice to prevent typo's)
example: "053395"
name:
type: string
description: Should consist of at least two words (first name and last name)
example: John Doe
birthDate:
type: string
format: date
description: Should be a date between 1900-01-01 and today, in the format `YYYY-MM-DD`
example: 2000-01-01
photo:
type: string
description: Should be a JPG image, with a filesize of max. 512KB and resolution between 520x520 and 720x720 pixels
format: binary
encoding:
photo:
contentType: image/jpeg
responses:
'201':
description: Created
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
tags:
- Personal Data APIs for touchpoints
summary: Retrieve the decrypted Personal Data for the given xTAT, using the OTP for verification of ownership.
description: OTP challenge is required to retrieve the Personal Data.
operationId: GetDecryptedPersonalData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
format: uuid
example: 'c3a6c0f2-3b6a-4b9a-9c5d-5d9c6b3a4c5d'
- name: otp
in: query
required: true
description: OTP challenge code that the token owner received in their e-mail inbox. OTP is always required for managing existing Personal Data.
schema:
type: string
pattern: ^[0-9]{6}$
example: "053395"
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/DecryptedPersonalData'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
patch:
tags:
- Personal Data APIs for touchpoints
summary: Update the supplied personal data for the given xTAT, using the OTP for verification of ownership.
description: This is a PATCH call, so only the personal data that the user desires to change need to be supplied. Integration layer supplements with any other existing personal data to be able to call GBO (PUT call).
operationId: UpdatePersonalData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
format: uuid
example: 'c3a6c0f2-3b6a-4b9a-9c5d-5d9c6b3a4c5d'
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- otp
properties:
otp:
type: string
pattern: ^[0-9]{6}$
description: OTP challenge code that the token owner received in their e-mail inbox. OTP is always required for managing existing Personal Data.
example: "053395"
name:
type: string
description: Should consist of at least two words (first name and last name)
example: John Doe
birthDate:
type: string
format: date
description: Should be a date between 1900-01-01 and today, in the format `YYYY-MM-DD`
example: 2000-01-01
photo:
type: string
description: Should be a JPG image, with a filesize of max. 512KB and resolution between 520x520 and 720x720 pixels
format: binary
encoding:
photo:
contentType: image/jpeg
responses:
'200':
description: OK
/personal-data/generate-otp:
get:
tags:
- Personal Data APIs for touchpoints
summary: Trigger OTP email for the given xTAT or e-mail address, to prove ownership
operationId: GenerateOtp
description: |-
Generate an OTP challenge e-mail to prove ownership of the given e-mail address or xTAT.\
Only one type of parameter can be supplied, either xtat or email. When both are supplied, an error is thrown.
parameters:
- name: xtat
in: query
required: false
schema:
type: string
format: uuid
example: 'c3a6c0f2-3b6a-4b9a-9c5d-5d9c6b3a4c5d'
- name: email
in: query
required: false
schema:
type: string
format: email
example: 'sV4yj@example.com'
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/OtpResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/personal-data/{xtat}/administrative-data:
get:
tags:
- Personal Data APIs for Service Engine
summary: API 1211 - Get Administrative Data
description: Integration Layer utilizes PAD management V2 in GBO APIM (`/pad-management/v2/..`)
operationId: GetAdministrativeData
parameters:
- name: xtat
description: xTAT to get administrative data for
in: path
required: true
schema:
type: string
format: uuid
example: 'c3a6c0f2-3b6a-4b9a-9c5d-5d9c6b3a4c5d'
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/AdministrativeData"
examples:
Valid and complete PAD:
summary: Valid and complete PAD
value:
name:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 5
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
birthdate:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
Partially filled PAD (no photo):
summary: Partially filled PAD (no photo)
value:
name:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo: null
birthdate:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
Flagged PAD:
summary: Flagged PAD
value:
name:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid name"
inaccuracyFlagCounter: 1
changeCounter: 1
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid photo"
inaccuracyFlagCounter: 1
changeCounter: 0
maxUpdatesVerificationCount: 5
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
birthdate:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid birthdate"
inaccuracyFlagCounter: 1
changeCounter: 2
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
Invalid UUID:
summary: Invalid UUID
value:
errors:
code: "0x03000103"
data: [
"geen-uuid"
]
message: "The provided scTat is not a valid UUID"
exceptionClassName: "PadpConstraintViolationException"
exceptionStackTrace: "not available because debug mode is turned off"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
No PAD found for xTAT:
summary: No PAD found for xTAT
value:
errors:
code: "0x03000105"
data: []
message: "Transit account not found"
exceptionClassName: "PadpEntityNotFoundException"
exceptionStackTrace: "not available because debug mode is turned off"
"500":
description: Internal Server Error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
Unknown xTAT:
summary: Unknown xTAT
value:
errors:
code: "0x00000001"
data: null
message: "400 : \"{\"errorMessage\":{\"referenceId\":\"076f0de4-df33-42a3-add0-def971ab6679\",\"message\":\"Unknown external transit account token.\"},\"businessExceptions\":[{\"code\":\"TM0207\",\"message\":\"Unknown external transit account token.\"}]}\""
exceptionClassName: "BadRequest"
exceptionStackTrace: "not available because debug mode is turned off"
components:
schemas:
AdministrativeData:
type: object
properties:
name:
$ref: '#/components/schemas/AdministrativeDataElement'
photo:
$ref: '#/components/schemas/AdministrativeDataElement'
birthdate:
$ref: '#/components/schemas/AdministrativeDataElement'
additionalProperties: false
AdministrativeDataElement:
type: object
properties:
inaccuracyFlag:
type: boolean
inaccuracyFlagReason:
type: string
nullable: true
inaccuracyFlagCounter:
type: integer
format: int32
changeCounter:
type: integer
format: int32
maxUpdatesVerificationCount:
type: integer
format: int32
lastChangeDate:
type: string
format: date-time
isValidated:
type: boolean
additionalProperties: false
DecryptedData:
type: object
properties:
name:
type: string
nullable: true
birthdate:
type: string
nullable: true
photo:
type: string
description: Base64 encoded photo
format: byte
nullable: true
additionalProperties: false
DecryptedPersonalData:
type: object
properties:
decryptedData:
$ref: '#/components/schemas/DecryptedData'
additionalProperties: false
Error:
type: object
properties:
code:
type: string
nullable: true
data:
type: array
items:
type: string
nullable: true
message:
type: string
nullable: true
additionalProperties: false
ErrorResponse:
type: object
properties:
errors:
type: array
items:
$ref: '#/components/schemas/Error'
nullable: true
exceptionClassName:
type: string
nullable: true
exceptionStackTrace:
type: string
nullable: true
additionalProperties: false
Metadata:
type: object
properties:
encryptedEphemeralKey:
type: string
nullable: true
additionalProperties: false
OtpResponse:
type: object
properties:
maskedEmailAddress:
type: string
nullable: true
additionalProperties: false

View File

@ -0,0 +1,477 @@
openapi: 3.0.3
info:
title: ABT GBO APIM APIs
description: APIs for calling GBO APIM - internal use only, these are NOT the functional APIs to be used by touchpoints!
version: "1.0"
servers:
- url: https://api.integratielaag.nl/abt/gboapim/1.0
paths:
/pad-management/v2/personal-data/{xtat}/administrative-data:
servers:
- url: https://api.integratielaag.nl/abt/serviceengine
description: APIPRODUCT ABT Service Engine Portal
- url: https://api.integratielaag.nl/abt/gboapim/1.0
description: API ABT GBO APIM
get:
tags:
- API WSO2 - GBO APIM
summary: API 1211 - Get Administrative Data
operationId: ABTPAD-GetAdministrativeData
parameters:
- name: xtat
description: xTAT to get administrative data for
in: path
required: true
schema:
type: string
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/AdministrativeData"
examples:
Valid and complete PAD:
summary: Valid and complete PAD
value:
name:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 5
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
birthdate:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
Partially filled PAD (no photo):
summary: Partially filled PAD (no photo)
value:
name:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo: null
birthdate:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
Flagged PAD:
summary: Flagged PAD
value:
name:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid name"
inaccuracyFlagCounter: 1
changeCounter: 1
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid photo"
inaccuracyFlagCounter: 1
changeCounter: 0
maxUpdatesVerificationCount: 5
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
birthdate:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid birthdate"
inaccuracyFlagCounter: 1
changeCounter: 2
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
Invalid UUID:
summary: Invalid UUID
value:
errors:
code: "0x03000103"
data: [
"geen-uuid"
]
message: "The provided scTat is not a valid UUID"
exceptionClassName: "PadpConstraintViolationException"
exceptionStackTrace: "not available because debug mode is turned off"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
No PAD found for xTAT:
summary: No PAD found for xTAT
value:
errors:
code: "0x03000105"
data: []
message: "Transit account not found"
exceptionClassName: "PadpEntityNotFoundException"
exceptionStackTrace: "not available because debug mode is turned off"
"500":
description: Internal Server Error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
Unknown xTAT:
summary: Unknown xTAT
value:
errors:
code: "0x00000001"
data: null
message: "400 : \"{\"errorMessage\":{\"referenceId\":\"076f0de4-df33-42a3-add0-def971ab6679\",\"message\":\"Unknown external transit account token.\"},\"businessExceptions\":[{\"code\":\"TM0207\",\"message\":\"Unknown external transit account token.\"}]}\""
exceptionClassName: "BadRequest"
exceptionStackTrace: "not available because debug mode is turned off"
/internal/b2b-client-authentication/v1/token/idp/b2b-access-token:
servers:
- url: https://only-for-internal-use.com
get:
tags:
- Internal DHIL use only - Raw GBO APIM
summary: API 1020 - Get B2B Access Token
description: Returns a client access token, needed for most other PADP APIs.
operationId: GetB2bAccessToken
parameters:
- name: APIKey
description: B2B IDP APIM Product API Key
in: header
required: true
schema:
type: string
- name: grant_type
description: A grant_type IS A string THAT defines the method which is used by client to request Access Token. grant_type = client_credentials - is used for M2M communication
in: query
required: true
example: client_credentials
schema:
type: string
- name: client_id
description: A client_id IS A string THAT is a unique identifier of the client application
in: query
required: true
schema:
type: string
- name: client_secret
description: A client_secret IS A unique identifier THAT is issued by IDP server on client registertraion and known only to Client and IDP server
in: query
required: true
schema:
type: string
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/B2bAccessToken"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
"500":
description: Internal Server Error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
/internal/pad-management/v2/personal-data/{xtat}/administrative-data:
servers:
- url: https://only-for-internal-use.com
get:
tags:
- Internal DHIL use only - Raw GBO APIM
summary: API 1211 - Get Administrative Data
operationId: InternalGBOAPIM-GetAdministrativeData
parameters:
- name: xtat
description: xTAT to get administrative data for
in: path
required: true
schema:
type: string
- name: APIKey
description: PADP APIM Product API Key
in: header
required: true
schema:
type: string
- name: Authorization
description: B2B Client Access Token, without the 'Bearer ' prefix
in: header
required: true
schema:
type: string
- name: requestId
description: A unique identifier for the request
in: header
required: true
schema:
type: string
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/AdministrativeData"
examples:
Valid and complete PAD:
summary: Valid and complete PAD
value:
name:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 5
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
birthdate:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
Partially filled PAD (no photo):
summary: Partially filled PAD (no photo)
value:
name:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo: null
birthdate:
inaccuracyFlag: false
inaccuracyFlagReason: null
inaccuracyFlagCounter: 0
changeCounter: 0
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
Flagged PAD:
summary: Flagged PAD
value:
name:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid name"
inaccuracyFlagCounter: 1
changeCounter: 1
maxUpdatesVerificationCount: 1
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
photo:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid photo"
inaccuracyFlagCounter: 1
changeCounter: 0
maxUpdatesVerificationCount: 5
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
birthdate:
inaccuracyFlag: true
inaccuracyFlagReason: "Invalid birthdate"
inaccuracyFlagCounter: 1
changeCounter: 2
maxUpdatesVerificationCount: 3
lastChangeDate: "2025-03-26T10:18:42.947"
isValidated: false
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
Invalid UUID:
summary: Invalid UUID
value:
errors:
code: "0x03000103"
data: [
"geen-uuid"
]
message: "The provided scTat is not a valid UUID"
exceptionClassName: "PadpConstraintViolationException"
exceptionStackTrace: "not available because debug mode is turned off"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
No PAD found for xTAT:
summary: No PAD found for xTAT
value:
errors:
code: "0x03000105"
data: []
message: "Transit account not found"
exceptionClassName: "PadpEntityNotFoundException"
exceptionStackTrace: "not available because debug mode is turned off"
"500":
description: Internal Server Error
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"
examples:
Unknown xTAT:
summary: Unknown xTAT
value:
errors:
code: "0x00000001"
data: null
message: "400 : \"{\"errorMessage\":{\"referenceId\":\"076f0de4-df33-42a3-add0-def971ab6679\",\"message\":\"Unknown external transit account token.\"},\"businessExceptions\":[{\"code\":\"TM0207\",\"message\":\"Unknown external transit account token.\"}]}\""
exceptionClassName: "BadRequest"
exceptionStackTrace: "not available because debug mode is turned off"
components:
schemas:
AdministrativeData:
type: object
properties:
name:
$ref: "#/components/schemas/AdministrativeData_AdministrativeDataElement"
photo:
$ref: "#/components/schemas/AdministrativeData_AdministrativeDataElement"
birthdate:
$ref: "#/components/schemas/AdministrativeData_AdministrativeDataElement"
additionalProperties: false
AdministrativeData_AdministrativeDataElement:
type: object
properties:
inaccuracyFlag:
type: boolean
inaccuracyFlagReason:
type: string
nullable: true
inaccuracyFlagCounter:
type: integer
format: int32
changeCounter:
type: integer
format: int32
maxUpdatesVerificationCount:
type: integer
format: int32
lastChangeDate:
type: string
format: date-time
isValidated:
type: boolean
additionalProperties: false
B2bAccessToken:
type: object
properties:
access_token:
type: string
nullable: true
expires_in:
type: integer
format: int32
refresh_expires_in:
type: integer
format: int32
refresh_token:
type: string
nullable: true
token_type:
type: string
nullable: true
not-before-policy:
type: integer
format: int32
scope:
type: string
nullable: true
BE_ID:
type: string
nullable: true
additionalProperties: false
ErrorResponse:
type: object
properties:
errors:
type: array
items:
$ref: "#/components/schemas/ErrorResponse_Error"
nullable: true
exceptionClassName:
type: string
nullable: true
exceptionStackTrace:
type: string
nullable: true
additionalProperties: false
ErrorResponse_Error:
type: object
properties:
code:
type: string
nullable: true
data:
type: array
items:
type: string
nullable: true
message:
type: string
nullable: true
additionalProperties: false

View File

@ -0,0 +1,267 @@
openapi: 3.0.1
info:
title: ClaimsAPI
version: '1.0'
servers:
- url: https://services.acc.api.htm.nl/chipkaart/1.0
security:
- default: []
tags:
- name: Claims
paths:
/claims:
post:
tags:
- Claims
summary: Create a claim
description: >
Create a claim by sending a JSON as specified in the schema. By
specifying the chipcardnumber under 'chipkaart',
a claim for OV chipcard will be send to the OVC API. If no
chipcardnumber is specified under 'chipkaart', a claim for EMV is send
to mendix.
parameters: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/claimsEntity'
examples:
OVCK:
value:
aankomsthalte: '1'
instapdatum: '2024-03-06T15:20:44.549Z'
instaptijd: '2024-03-06T15:20:44.549Z'
ingecheckt: true
uitgecheckt: true
chipkaart: '1234123412341234'
afgeschrevenbedrag: 0
vertrekhalte: string
korting: true
iban: '1234123412341234'
naam: string
emailadres: user@example.com
uitstaptijd: '2024-03-06T15:20:44.549Z'
verwachtbedrag: 0
toelichting: string
lijn: '1'
vervoertype: '1'
serviceRefId: '1'
Totaalbedrag: 0
EMV:
value:
aankomsthalte: '1'
instapdatum: '2024-03-06T15:20:44.549Z'
instaptijd: '2024-03-06T15:20:44.549Z'
ingecheckt: true
uitgecheckt: true
afgeschrevenbedrag: 0
vertrekhalte: string
korting: true
iban: '1234123412341234'
naam: string
emailadres: user@example.com
uitstaptijd: '2024-03-06T15:20:44.549Z'
verwachtbedrag: 0
toelichting: string
lijn: '1'
vervoertype: '1'
serviceRefId: '1'
Totaalbedrag: 0
responses:
'200':
description: ok
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/refunds:
post:
tags:
- Claims
summary: Create a refund request
description: Create a refund request by sending a JSON as specified in the schema. Either a serviceReferenceId or ovPasNumber should be present in order to fulfill the refund request.
parameters: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/refundsEntity'
examples:
EMV:
value:
emailAddress: 'j.beek@htm.nl'
orderNumber: 'ORD1000046'
serviceReferenceId: 'NLOVA5BCD124H3Z21X'
amount: 2305
iban: 'NL98INGB0003856625'
orderDate: '2025-01-13'
productName: 'HTM 20% korting'
OVpas:
value:
emailAddress: 'j.beek@htm.nl'
orderNumber: 'ORD1000046'
ovpasNumber: '63AW974'
iban: 'NL98INGB0003856625'
orderDate: '2025-01-13'
productName: 'HTM 20% korting'
responses:
'201':
description: Created
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
components:
schemas:
claimsEntity:
required:
- Totaalbedrag
- aankomsthalte
- afgeschrevenbedrag
- emailadres
- instapdatum
- instaptijd
- korting
- lijn
- serviceRefId
- toelichting
- uitgecheckt
- vertrekhalte
- vervoertype
- verwachtbedrag
type: object
properties:
aankomsthalte:
type: string
instapdatum:
type: string
format: date-time
instaptijd:
type: string
format: date-time
ingecheckt:
type: boolean
uitgecheckt:
type: boolean
chipkaart:
type: string
afgeschrevenbedrag:
type: number
format: float
vertrekhalte:
type: string
korting:
type: boolean
iban:
type: string
description: String of length between 15 en 32 characters
example: '1234123412341234'
naam:
type: string
emailadres:
type: string
format: email
uitstaptijd:
type: string
format: date-time
verwachtbedrag:
type: number
format: float
toelichting:
type: string
lijn:
type: string
vervoertype:
type: string
serviceRefId:
type: string
Totaalbedrag:
type: number
format: float
refundsEntity:
required:
- emailAddress
- iban
type: object
properties:
emailAddress:
type: string
format: email
example: j.beek@htm.nl
orderNumber:
type: string
example: ORD1000046
serviceReferenceId:
type: string
example: NLOVA5BCD124H3Z21X
amount:
type: integer
example: 12305
ovpasNumber:
type: string
example: 63AW974
iban:
type: string
example: NL00RABO000001337
orderDate:
type: string
format: date
example: 2025-01-13
productName:
type: string
example: HTM 20% korting
401Response:
type: object
properties:
code:
type: string
example: '900901'
type:
type: string
message:
type: string
example: Invalid Credentials
description:
type: string
example: >-
Invalid Credentials. Make sure you have provided the correct
security credentials
500Response:
type: object
properties:
error:
type: string
example: error while connecting to backend
securitySchemes:
default:
type: oauth2
flows:
implicit:
authorizationUrl: https://services.acc.api.htm.nl/authorize
scopes: {}

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@ info:
version: "1.0" version: "1.0"
description: Service Engine APIs for ABT Contracts v2. These are NOT the CRUD APIs to the data hub. description: Service Engine APIs for ABT Contracts v2. These are NOT the CRUD APIs to the data hub.
servers: servers:
- url: https://api.integratielaag.nl/v1 - url: https://services.acc.api.htm.nl/abt/touchpoint/1.0
paths: paths:
/customers/contracts: /customers/contracts:
parameters: parameters:
@ -27,42 +27,65 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/unavailable" $ref: "#/components/schemas/unavailable"
example: examples:
[ List all contracts for a single customer profile:
{ summary: List all contracts for a single customer profile
"contractId": "5a3876a1-e9a1-4278-8983-4679a8d583c2", description: |
"contractNumber": "D123456", List all contracts for single customer profile with customer
"customerProfileId": 42, number 'D123456'.
"orderId": "eb3d08f7-7feb-4f31-9f5b-daa634e51f48", value:
"orderLineId": "52efbbfc-8c28-4016-9ece-dc3ef9a70bd8", [
"touchpointId": 2, {
"contractStatus": "contractId": "5a3876a1-e9a1-4278-8983-4679a8d583c2",
{ "contractStatusId": 2, "name": "active" }, "contractNumber": "D123456",
"productId": 1, "customerProfileId": 42,
"productName": "HTM Maand 20% korting", "orderId": "eb3d08f7-7feb-4f31-9f5b-daa634e51f48",
"termDuration": "P0Y1M0D", "orderLineId": "52efbbfc-8c28-4016-9ece-dc3ef9a70bd8",
"billingDay": 15, "touchpointId": 2,
"highestInvoiceTerm": 1, "contractStatus":
"xSpit": "1c345237-4d84-47f0-93c2-7b94338e3355", { "contractStatusId": 2, "name": "active" },
"created": "2024-08-01 15:01:00.000", "productId": 1,
}, "productName": "HTM Maand 20% korting",
{ "termDuration": "P0Y1M0D",
"contractId": "f07253e6-c364-474c-a342-a10a4a7cf305", "billingDay": 15,
"contractNumber": "D123456", "highestInvoiceTerm": 1,
"customerProfileId": 42, "created": "2024-08-01 15:01:00.000",
"orderId": "945d43e6-516e-425b-8847-9aba41289acd", "ovPayTokenId": 1337,
"orderLineId": "42f68042-908f-41f4-9d9b-4cab843ff0e8", "_links":
"touchpointId": 2, {
"contractStatus": { "contractStatusId": 1, "name": "new" }, "get_token":
"productId": 1, {
"productName": "HTM Maand 20% korting", "href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPayTokenId=1337",
"termDuration": "P0Y1M0D", "method": "GET",
"billingDay": 15, },
"highestInvoiceTerm": 1, },
"xSpit": "1c345237-4d84-47f0-93c2-7b94338e3355", },
"created": "2024-08-01 15:01:00.000", {
}, "contractId": "f07253e6-c364-474c-a342-a10a4a7cf305",
] "contractNumber": "D123456",
"customerProfileId": 42,
"orderId": "945d43e6-516e-425b-8847-9aba41289acd",
"orderLineId": "42f68042-908f-41f4-9d9b-4cab843ff0e8",
"touchpointId": 2,
"contractStatus":
{ "contractStatusId": 1, "name": "new" },
"productId": 1,
"productName": "HTM Maand 20% korting",
"termDuration": "P0Y1M0D",
"billingDay": 15,
"highestInvoiceTerm": 1,
"created": "2024-08-01 15:01:00.000",
"ovPayTokenId": 1338,
"_links":
{
"get_token":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPayTokenId=1338",
"method": "GET",
},
},
},
]
/customers/contracts/{contractId}: /customers/contracts/{contractId}:
parameters: parameters:
- in: header - in: header
@ -114,76 +137,96 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/unavailable" $ref: "#/components/schemas/unavailable"
example: examples:
{ Full contract details of a single contract:
"contractId": "5a3876a1-e9a1-4278-8983-4679a8d583c2", summary: Full contract details of a single contract
"contractNumber": "D123456", description: |
"customerProfileId": 42, Full contract details of a single contract with contract
"orderId": "eb3d08f7-7feb-4f31-9f5b-daa634e51f48", number 'D123456'.
"orderLineId": "52efbbfc-8c28-4016-9ece-dc3ef9a70bd8", value:
"touchpointId": 2, {
"contractStatus": { "contractStatusId": 2, "name": "active" }, "contractId": "5a3876a1-e9a1-4278-8983-4679a8d583c2",
"productId": 1, "contractNumber": "D123456",
"productName": "HTM Maand 20% korting", "customerProfileId": 42,
"termDuration": "P0Y1M0D", "orderId": "eb3d08f7-7feb-4f31-9f5b-daa634e51f48",
"billingDay": 15, "orderLineId": "52efbbfc-8c28-4016-9ece-dc3ef9a70bd8",
"highestInvoiceTerm": 1, "touchpointId": 2,
"xSpit": "1c345237-4d84-47f0-93c2-7b94338e3355", "contractStatus":
"contractVersions": { "contractStatusId": 2, "name": "active" },
[ "productId": 1,
{ "productName": "HTM Maand 20% korting",
"contractVersionId": 1, "termDuration": "P0Y1M0D",
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/", "billingDay": 15,
"termAmountExclTax": 1200, "highestInvoiceTerm": 1,
"taxCode": "V21", "ovPayTokenId": 1337,
"taxAmount": 108, "contractVersions":
"termAmountInclTax": 1308, [
"start": "2024-07-04 15:01:00.000", {
"end": "2024-12-31 15:01:00.000", "contractVersionId": 1,
}, "termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
{ "productId": 1,
"contractVersionId": 2, "productName": "HTM Maand 20% korting",
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/", "taxCode": "V9",
"termAmountExclTax": 1300, "taxPercentage": 9.0,
"taxCode": "V21", "termAmountInclTax": 400,
"taxAmount": 117, "start": "2024-07-04 15:01:00.000",
"termAmountInclTax": 1417, "end": "2024-12-31 15:01:00.000",
"start": "2025-01-01 15:01:00.000", },
}, {
], "contractVersionId": 2,
"contractActions": "termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
[ "productId": 1,
{ "productName": "HTM Maand 20% korting",
"contractActionId": "67687851-59dd-4bbc-aa74-0f7abd26c883", "taxCode": "V9",
"actionType": { "actionTypeId": 1, "name": "create" }, "taxPercentage": 9.0,
"user": "subid123456", "termAmountInclTax": 400,
"timestamp": "2024-07-02 15:01:00.000", "start": "2025-01-01 15:01:00.000",
"details": "Contract created", },
"correlationId": "976e7a4c-bf24-43d2-b444-55817556e7ee", ],
}, "contractActions":
{ [
"contractActionId": "ea9ad287-9cd3-4e76-bcb9-d71db551cf55", {
"actionType": { "actionTypeId": 2, "name": "change" }, "contractActionId": "67687851-59dd-4bbc-aa74-0f7abd26c883",
"user": "subid123456", "actionType":
"timestamp": "2024-07-03 15:01:00.000", { "actionTypeId": 1, "name": "create" },
"details": "Contract changed", "user": "subid123456",
"correlationId": "e2462347-6749-4841-b42a-cf8de19ec727", "timestamp": "2024-07-02 15:01:00.000",
}, "details": "Contract created",
], "correlationId": "976e7a4c-bf24-43d2-b444-55817556e7ee",
"contractInvoices": },
[ {
{ "contractActionId": "ea9ad287-9cd3-4e76-bcb9-d71db551cf55",
"contractInvoiceId": "8699d72a-cf4d-4e6b-9e9c-549d837ca51f", "actionType":
"externalReference": "F2024-0001", { "actionTypeId": 2, "name": "change" },
"term": 1, "user": "subid123456",
"created": "2024-07-02 15:01:00.000", "timestamp": "2024-07-03 15:01:00.000",
"updated": "2024-07-02 15:01:00.000", "details": "Contract changed",
"state": "invoice_created", "correlationId": "e2462347-6749-4841-b42a-cf8de19ec727",
"data": "{json}", },
"isCredit": false, ],
}, "contractInvoices":
], [
} {
"contractInvoiceId": "8699d72a-cf4d-4e6b-9e9c-549d837ca51f",
"externalReference": "F2024-0001",
"term": 1,
"invoiceDate": "2024-07-02",
"created": "2024-07-02 15:01:00.000",
"updated": "2024-07-02 15:01:00.000",
"state": "invoice_created",
"data": "{json}",
"isCredit": false,
},
],
"_links":
{
"get_token":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPayTokenId=1337",
"method": "GET",
},
},
}
/customers/contracts/{contractId}/invoices: /customers/contracts/{contractId}/invoices:
parameters: parameters:
- in: header - in: header
@ -213,31 +256,572 @@ paths:
application/json: application/json:
schema: schema:
$ref: "#/components/schemas/unavailable" $ref: "#/components/schemas/unavailable"
example: examples:
[ Get all invoices of a single contract:
summary: Get all invoices of a single contract
description: |
Get all invoices of a single contract with contract number
'D123456'.
value:
[
{
"contractInvoiceId": "8699d72a-cf4d-4e6b-9e9c-549d837ca51f",
"contractId": "9e224750-3065-471d-af57-85b9cffa7c89",
"externalReference": "F2024-0001",
"term": 1,
"invoiceDate": "2024-07-02",
"created": "2024-07-02 15:01:34.000",
"updated": "2024-07-04 00:04:56.000",
"state": "invoice_created",
"public_link": "http://mijnfactuurinzien.nl/F2024-0001",
"isCredit": false,
},
{
"contractInvoiceId": "0e729101-2c84-44db-8b18-d8f759e968e0",
"contractId": "9e224750-3065-471d-af57-85b9cffa7c89",
"externalReference": "F2024-0002",
"term": 2,
"invoiceDate": "2024-08-02",
"created": "2024-08-02 15:01:34.000",
"updated": "2024-08-04 00:04:56.000",
"state": "invoice_created",
"public_link": "http://mijnfactuurinzien.nl/F2024-0002",
"isCredit": false,
},
]
/contracts/{contractId}/cancellationmoments:
parameters:
- in: header
name: X-HTM-JWT-AUTH-HEADER
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: true
description: The JWT of the logged in customer.
- in: path
name: contractId
schema:
type: string
format: uuid
example: 9e224750-3065-471d-af57-85b9cffa7c89
required: true
description: The id of the contract to process.
get:
summary: Get all cancellation moments for a given contract.
description: Get all cancellation moments for a given contract.
tags:
- SE Contract Cancellation v2
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
All cancellation moments of a term bound contract:
summary: All cancellation moments of a term bound contract
description: |
All cancellation moments of a term bound contract.
value:
{
"cancellationMoment": "termBound",
"termDuration": "P1M",
"billingDay": 18,
"cancellationFrom": "2024-08-10T00:00:00",
"cancellationUntil": "2026-08-10T00:00:00",
}
/contracts/{contractId}/cancellationvalidation:
parameters:
- in: header
name: X-HTM-JWT-AUTH-HEADER
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: true
description: The JWT of the logged in customer.
- in: path
name: contractId
schema:
type: string
format: uuid
example: 9e224750-3065-471d-af57-85b9cffa7c89
required: true
description: The id of the contract to process.
post:
summary: Validate a cancellation for a given contract.
description: Validate a cancellation for a given contract.
tags:
- SE Contract Cancellation v2
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
Validate a cancellation of a given end date:
summary: Validate a cancellation of a given end date
description: |
Validate a cancellation of a given end date.
value: { "end": "2024-08-10T00:00:00" }
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
Successfully validated cancellation:
summary: Successfully validated cancellation
description: |
Successfully validated a cancellation. The response contains
the refund amount and refund methods.
value:
{
"validationResult": true,
"validationMessage": "",
"end": "2024-08-10T03:59:59",
"refundAmount": 2489,
"refundMethods": ["creditInvoice", "iDeal"],
}
Unsuccesful validation:
summary: Unsuccesful validation
description: |
Unsuccesful validation. The response contains the error message.
value:
{
"validationResult": false,
"validationMessage": "Cancellation end date not allowed",
"end": null,
"refundAmount": null,
"refundMethods": [],
}
/contracts/{contractId}/cancellation:
parameters:
- in: header
name: X-HTM-JWT-AUTH-HEADER
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: true
description: The JWT of the logged in customer.
- in: path
name: contractId
schema:
type: string
format: uuid
example: 9e224750-3065-471d-af57-85b9cffa7c89
required: true
description: The id of the contract to process.
post:
summary: Cancel a contract.
description: Cancel a contract.
tags:
- SE Contract Cancellation v2
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
Cancellation request for credit invoice:
summary: Cancellation request for credit invoice
description: |
Cancellation request for credit invoice.
value:
{ {
"contractInvoiceId": "8699d72a-cf4d-4e6b-9e9c-549d837ca51f", "end": "2024-08-10T00:00:00",
"contractId": "9e224750-3065-471d-af57-85b9cffa7c89", "refundMethod": "creditInvoice",
"externalReference": "F2024-0001", }
"term": 1, responses:
"created": "2024-07-02 15:01:34.000", "200":
"updated": "2024-07-04 00:04:56.000", description: OK
"state": "invoice_created", content:
"public_link": "http://mijnfactuurinzien.nl/F2024-0001", application/json:
"isCredit": false, schema:
}, $ref: "#/components/schemas/unavailable"
{ examples:
"contractInvoiceId": "0e729101-2c84-44db-8b18-d8f759e968e0", Successfully cancelled contract:
"contractId": "9e224750-3065-471d-af57-85b9cffa7c89", summary: Successfully cancelled contract
"externalReference": "F2024-0002", description: |
"term": 2, Successfully cancelled a contract. The response contains
"created": "2024-08-02 15:01:34.000", the refund amount and refund method.
"updated": "2024-08-04 00:04:56.000", value:
"state": "invoice_created", {
"public_link": "http://mijnfactuurinzien.nl/F2024-0002", "end": "2024-08-10T03:59:59",
"isCredit": false, "refundAmount": 2489,
}, "refundMethod": "creditInvoice",
] }
/contracts/{contractId}/undocancellation:
parameters:
- in: header
name: X-HTM-JWT-AUTH-HEADER
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: true
description: The JWT of the logged in customer.
- in: path
name: contractId
schema:
type: string
format: uuid
example: 9e224750-3065-471d-af57-85b9cffa7c89
required: true
description: The id of the contract to process.
post:
summary: Undo a pending cancellation of a contract.
description: Undo a pending cancellation of a contract.
tags:
- SE Contract Cancellation v2
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
Successfully undid cancellation of contract:
summary: Successfully undid pending cancellation
description: |
Successfully undid a pending cancellation of a contract. The contract
is active again.
value:
{
"contractId": "9e224750-3065-471d-af57-85b9cffa7c89",
"contractNumber": "D123456",
"customerProfileId": 42,
"orderId": "eb3d08f7-7feb-4f31-9f5b-daa634e51f48",
"orderLineId": "52efbbfc-8c28-4016-9ece-dc3ef9a70bd8",
"touchpointId": 2,
"contractStatus":
{ "contractStatusId": 2, "name": "active" },
"productId": 1,
"productName": "HTM Maand 20% korting",
"termDuration": "P0Y1M0D",
"billingDay": 15,
"highestInvoiceTerm": 1,
"ovPayTokenId": 1337,
"contractVersions":
[
{
"contractVersionId": 1,
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
"productId": 1,
"productName": "HTM Maand 20% korting",
"taxCode": "V9",
"taxPercentage": 9.0,
"termAmountInclTax": 400,
"start": "2024-07-04 15:01:00.000",
"end": "2024-12-31 15:01:00.000",
},
{
"contractVersionId": 2,
"termsAndConditions": "https://www.htm.nl/reisproducten/productvoorwaarden/htm-maandkorting/",
"productId": 1,
"productName": "HTM Maand 20% korting",
"taxCode": "V9",
"taxPercentage": 9.0,
"termAmountInclTax": 400,
"start": "2025-01-01 15:01:00.000",
},
],
"contractActions":
[
{
"contractActionId": "67687851-59dd-4bbc-aa74-0f7abd26c883",
"actionType":
{ "actionTypeId": 1, "name": "create" },
"user": "subid123456",
"timestamp": "2024-07-02 15:01:00.000",
"details": "Contract created",
"correlationId": "976e7a4c-bf24-43d2-b444-55817556e7ee",
},
{
"contractActionId": "ea9ad287-9cd3-4e76-bcb9-d71db551cf55",
"actionType":
{ "actionTypeId": 2, "name": "change" },
"user": "subid123456",
"timestamp": "2024-07-03 15:01:00.000",
"details": "Contract changed",
"correlationId": "e2462347-6749-4841-b42a-cf8de19ec727",
},
],
"contractInvoices":
[
{
"contractInvoiceId": "8699d72a-cf4d-4e6b-9e9c-549d837ca51f",
"externalReference": "F2024-0001",
"term": 1,
"invoiceDate": "2024-07-02",
"created": "2024-07-02 15:01:00.000",
"updated": "2024-07-02 15:01:00.000",
"state": "invoice_created",
"data": "{json}",
"isCredit": false,
},
],
"_links":
{
"get_token":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/tokens?ovPayTokenId=1337",
"method": "GET",
},
},
}
/contractpayments:
parameters:
- in: header
name: X-HTM-JWT-AUTH-HEADER
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: true
description: The JWT of the logged in customer.
get:
summary: List all contract payments for a certain debtor.
description: |
List all contract payments for a certain debtor. The source of these payments is the accounts receivable management system (Payt).
tags:
- SE Contract Payments v2
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
Empty list:
summary: Empty list
description: List all contract payments for a debtor with no payments.
value: { "contractPayments": [] }
Successful direct debit:
summary: Successful direct debit
description: One payment for a debtor with a successful direct debit.
value:
{
"contractPayments":
[
{
"paymentId": "151845776",
"totalAmount": "26.62",
"paymentMethod": "Automatische incasso",
"paymentDate": "2024-09-12",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
],
}
Direct debit reversal:
summary: Direct debit reversal
description: One payment for a debtor with a reversed direct debit.
value:
{
"contractPayments":
[
{
"paymentId": "151845776",
"totalAmount": "-26.62",
"paymentMethod": "Stornering",
"paymentDate": "2024-09-12",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
],
}
iDEAL payment:
summary: iDEAL payment
description: One payment for a debtor with an iDEAL payment.
value:
{
"contractPayments":
[
{
"paymentId": "151845776",
"totalAmount": "26.62",
"paymentMethod": "iDEAL",
"paymentDate": "2024-09-12",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
],
}
Bank transfer:
summary: Bank transfer
description: One payment for a debtor with a bank transfer.
value:
{
"contractPayments":
[
{
"paymentId": "151845776",
"totalAmount": "26.62",
"paymentMethod": "Overboeking",
"paymentDate": "2024-09-12",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
],
}
List of four payments for one invoice:
summary: List of four payments for one invoice
description: Four payments for a debtor for one invoice; a direct debit, a direct debit reversal, a bank transfer and an iDEAL payment.
value:
{
"contractPayments":
[
{
"paymentId": "151845776",
"totalAmount": "26.62",
"paymentMethod": "Automatische incasso",
"paymentDate": "2024-09-12",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
{
"paymentId": "151845776",
"totalAmount": "-26.62",
"paymentMethod": "Stornering",
"paymentDate": "2024-09-12",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
{
"paymentId": "151845777",
"totalAmount": "10.00",
"paymentMethod": "Overboeking",
"paymentDate": "2024-09-13",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
{
"paymentId": "151845778",
"totalAmount": "16.62",
"paymentMethod": "iDEAL",
"paymentDate": "2024-09-14",
"iban": "NL25INGB******1337",
"invoice":
{
"invoiceId": "147722263",
"invoiceNumber": "F2024-0001",
"description": "HTM Maandkorting 20%",
"publicLink": "https://factuurinzien.nl/d/b0aac3f42f325f5dd6abc172f723caab5956524d/i/ddb245d6df67999eca48c4a71b5661b93038e20a",
},
"_links":
{
"get_contractdetails":
{
"href": "https://api.integratielaag.nl/abt/touchpoint/1.0/customers/contracts/5ca46c1a-cb9d-4c2d-960e-4471e8e28b6a",
"method": "GET",
},
},
},
],
}
components: components:
securitySchemes: securitySchemes:
bearerToken: bearerToken:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,568 @@
openapi: 3.0.1
info:
title: Service Engine APIs for Notifications
description: >-
Service Engine APIs for all HTM Notifications. These are NOT the CRUD APIs to access raw data in the database.
version: "1.0"
servers:
- url: https://services.acc.api.htm.nl/abt/touchpoint/2.0
tags:
- name: Notification categories
description: >-
Service Engine APIs for all HTM Notifications metadata. To build content only.
- name: Notification subscriptions
description: >-
Service Engine APIs for the HTM Notification subscriptions for a user. Contains the subscriptions on category level
- name: Notification preferences
description: >-
//future Service Engine APIs for the HTM Notification preferences for a category for a user. Contains the discrepancies from the default. or
paths:
/notificationcategories:
get:
tags:
- Notification categories
summary: Get notification categories and optins references for that category that a touchpoint can show.
description: |
Get notification categories that a touchpoint can show and optins ( eventTypes) and channels (eventType_channels) for the optin for that category
parameters:
- name: expand
in: query
schema:
type: string
enum: [none, eventType, eventTypeChannel]
default: none
responses:
"200":
description: OK
content:
application/json:
examples:
getNotifactionCategories?expand=none:
summary: Return all the notification categories without nested attributes (expand=none)
value:
notificationCategories:
- notificationCategoryId: 1
name: Mijn Reizen
- notificationCategoryId: 2
name: Nieuwsbrief aanmelding
- notificationCategoryId: 3
name: Mijn Passen
getNotifactionCategories?expand=eventType:
summary: Return all the notification categories with nested event types (expand=eventType)
value:
notificationCategories:
- notificationCategoryId: 1
name: Mijn Reizen
eventTypes:
- eventTypeId: 2
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, TRAVEL_SCHEME
subName: CI
prettyName: Check In
optinRequired: false
- eventTypeId: 3
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, PAD
subName: null
prettyName: Profielgegevens op de pas
optinRequired: false
- notificationCategoryId: 2
name: Nieuwsbrief aanmelding
eventTypes:
- eventTypeId: 1
eventOrigin:
eventOriginId: 6
name: Maileon
name: newsletter
subName: null
prettyName: HTM nieuwsbrief
optinRequired: false
- notificationCategoryId: 3
name: Mijn Passen
eventTypes:
- eventTypeId: 4
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, CARD
subName: null
prettyName: Mijn passen
optinRequired: false
- eventTypeId: 5
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, PAD
subName: null
prettyName: Profielgegevens op de pas
optinRequired: false
getNotifactionCategories?expand=eventTypeChannel:
summary: Return all the notification categories with all nested attributes (expand=eventTypeChannel)
value:
notificationCategories:
- notificationCategoryId: 1
name: Mijn Reizen
eventTypes:
- eventTypeId: 2
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, TRAVEL_SCHEME
subName: CI
prettyName: Check In
optinRequired: false
eventTypeChannels:
- eventTypeChannelId: ccc8c025-06b5-4928-a632-23e1c55cd173
channel:
channelId: 1
name: push
isDefault: true
isMandatory: false
- eventTypeChannelId: da2deb4c-ce77-4b5f-aecc-ddebfd14349d
channel:
channelId: 2
name: email
isDefault: false
isMandatory: false
- eventTypeId: 3
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, PAD
subName: null
prettyName: Profielgegevens op de pas
optinRequired: false
eventTypeChannels:
- eventTypeChannelId: 8e7df8f1-7e50-482f-8301-d399e75fd432
channel:
channelId: 1
name: push
isDefault: true
isMandatory: false
- eventTypeChannelId: 72960a92-1855-469f-9cfd-5d72f57106f2
channel:
channelId: 2
name: email
isDefault: false
isMandatory: false
- notificationCategoryId: 2
name: Nieuwsbrief aanmelding
eventTypes:
- eventTypeId: 1
eventOrigin:
eventOriginId: 6
name: Maileon
name: newsletter
subName: null
prettyName: HTM nieuwsbrief
optinRequired: false
eventTypeChannels:
- eventTypeChannelId: 447a1116-6cd7-4645-8c3d-43237b6186cd
channel:
channelId: 2
name: email
isDefault: true
isMandatory: false
- notificationCategoryId: 3
name: Mijn Passen
eventTypes:
- eventTypeId: 4
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, CARD
subName: null
prettyName: Mijn passen
optinRequired: false
eventTypeChannels:
- eventTypeChannelId: be07c7bb-714b-4637-acf5-a67025ad8e60
channel:
channelId: 1
name: push
isDefault: true
isMandatory: false
- eventTypeChannelId: 0c797b5a-ed34-494b-8c64-0a832830d392
channel:
channelId: 2
name: email
isDefault: false
isMandatory: false
- eventTypeId: 5
eventOrigin:
eventOriginId: 1
name: GBO
name: ALERTS, PAD
subName: null
prettyName: Profielgegevens op de pas
optinRequired: false
eventTypeChannels:
- eventTypeChannelId: b910368f-c045-4e8e-b01d-bcbc78708bac
channel:
channelId: 1
name: push
isDefault: true
isMandatory: false
- eventTypeChannelId: 93e773da-ba3b-48da-9a0e-ee478eaa752f
channel:
channelId: 2
name: email
isDefault: false
isMandatory: false
"404":
description: No notification category found
content:
application/json:
example:
{
"type": "https://api.integratielaag.nl/abt/touchpoint/2.0/notifications",
"title": "Niet gevonden",
"detail": "Notificatiecategorie niet gevonden",
"instance": "555d00b5-bc3f-4591-949b-479e76d49ea7",
"errors":
[
{
"code": "404",
"detail": null,
"path": null,
"parameter": null,
},
],
}
/notificationsubscriptions:
get:
tags:
- Notification subscriptions
summary: Get all possible notificationSubscriptions for a customer (account or private).
description: |
Get all possible notificationSubscriptions for a customer (account or private), including if they have opted-in for it.
parameters:
- name: X-HTM-JWT-AUTH-HEADER
in: header
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: false
description: The JWT of a customer in case of touchpoint were customer logs in themselves
- name: X-HTM-CUSTOMER-PROFILE-ID-HEADER
in: header
schema:
type: string
example: feaaef83-a551-4283-8419-340b1ada3b55
required: false
description: The customerProfileId of a customer in the case of the SMP
- name: X-HTM-ROLE-HEADER
in: header
schema:
type: string
example: Customer
required: false
description: The role of the HTM employee in the case of the SMP
- name: emailAddress
in: query
schema:
type: string
format: email
example: john.doe@mymailprovider.com
required: false
description: The emailadress of the customer in the case of anonymous opt-ins
responses:
"200":
description: OK
content:
application/json:
examples:
getNotifactionSubscriptionsAll:
summary: Return all the notification subscriptions where for each category the client has actively opted in or out - All
value:
{
"notificationSubscriptions":
[
{
"notificationSubscriptionId": "64047471-e0c3-4abc-b4eb-83a12a6de903",
"notificationCategory":
{
"notificationCategoryId": 1,
"name": "Mijn reizen",
},
"isActive": true,
},
{
"notificationSubscriptionId": "571388cd-8903-40d5-89e6-9191cb8d656e",
"notificationCategory":
{
"notificationCategoryId": 2,
"name": "Nieuwsbrief aanmelding",
},
"isActive": true,
},
{
"notificationSubscriptionId": "cf736ff2-2f8f-434e-a3c7-a14064b73c9b",
"notificationCategory":
{
"notificationCategoryId": 3,
"name": "Mijn contracten",
},
"isActive": false,
},
],
}
getNotifactionSubscriptionsSome:
summary: Return all the notification subscriptions where for each category the client has actively opted in or out - Some
value:
{
"notificationSubscriptions":
[
{
"notificationSubscriptionId": "64047471-e0c3-4abc-b4eb-83a12a6de903",
"notificationCategory":
{
"notificationCategoryId": 1,
"name": "Mijn reizen",
},
"isActive": true,
},
{
"notificationSubscriptionId": "cf736ff2-2f8f-434e-a3c7-a14064b73c9b",
"notificationCategory":
{
"notificationCategoryId": 2,
"name": "Nieuwsbrief aanmelding",
},
"isActive": false,
},
],
}
"403":
description: Forbidden // Als geverifieerd profiel gevonden wordt, maar niet op een geverifieerde manier benaderd wordt
content:
application/json:
example:
{
"type": "https://api.integratielaag.nl/abt/touchpoint/2.0/notifications",
"title": "Verboden",
"detail": "Niet toegestaan",
"instance": "555d00b5-bc3f-4591-949b-479e76d49ea7",
"errors":
[
{
"code": "403",
"detail": null,
"path": null,
"parameter": null,
},
],
}
"404":
description: No notification subscriptions found
content:
application/json:
example:
{
"type": "https://api.integratielaag.nl/abt/touchpoint/2.0/notifications",
"title": "Niet gevonden",
"detail": "Notificatie niet gevonden",
"instance": "555d00b5-bc3f-4591-949b-479e76d49ea7",
"errors":
[
{
"code": "404",
"detail": null,
"path": null,
"parameter": null,
},
],
}
post:
tags:
- Notification subscriptions
summary: Create a new notificationSubscription for a customer (account or private).
description: |
Create a notificationSubscriptions for a customer (account or private), including if they have opted-in for it.
parameters:
- name: X-HTM-JWT-AUTH-HEADER
in: header
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: false
description: The JWT of a customer in case of touchpoint were customer logs in themselves
- name: X-HTM-CUSTOMER-PROFILE-ID-HEADER
in: header
schema:
type: string
example: feaaef83-a551-4283-8419-340b1ada3b55
required: false
description: The customerProfileId of a customer in the case of the SMP
- name: X-HTM-ROLE-HEADER
in: header
schema:
type: string
example: Customer
required: false
description: The role of the HTM employee in the case of the SMP
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
Create notificationSubscription anonymous:
value:
{
"emailAddress": "anonymous@mymailprovider.com",
"notificationCategoryId": 1
}
Create notificationSubscription account active:
value: { "notificationCategoryId": 2 }
responses:
"201":
description: Created
content:
application/json:
examples:
Create notificationSubscription anonymous:
summary: Return the created notification for an anonymous user inactive by default.
value:
{
"notificationSubscriptionId": "e112f26e-37fa-4bde-8def-9977cd1d50ae",
"notificationCategory":
{
"notificationCategoryId": 2,
"name": "Nieuwsbrief aanmelding",
},
"isActive": False,
}
Create notificationSubscription account active:
summary: Return the created notification for an anonymous user active
value:
{
"notificationSubscriptionId": "6b88eba1-af1f-42fc-82d3-d7202d5f1afe",
"notificationCategory":
{ "notificationCategoryId": 2, "name": "Nieuwsbrief aanmelding" },
"isActive": True,
}
"405":
description: Method not allowed, ook als een notificatie aangemaakt wordt voor een account maar op een anonieme manier benadert wordt.
content:
application/json:
example:
{
"type": "https://api.integratielaag.nl/abt/touchpoint/2.0/notifications",
"title": "Methode niet toegestaan",
"detail": "",
"instance": "555d00b5-bc3f-4591-949b-479e76d49ea7",
"errors":
[
{
"code": "405",
"detail": null,
"path": null,
"parameter": null,
},
],
}
/notificationsubscriptions/{notificationSubscriptionId}:
patch:
tags:
- Notification subscriptions
summary: Update a notificationSubscription for a customer.
description: |
Update a notificationSubscription for a customer.
parameters:
- name: X-HTM-JWT-AUTH-HEADER
in: header
schema:
type: string
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
required: false
description: The JWT of a customer in case of touchpoint were customer logs in themselves
- name: X-HTM-CUSTOMER-PROFILE-ID-HEADER
in: header
schema:
type: string
example: feaaef83-a551-4283-8419-340b1ada3b55
required: false
description: The customerProfileId of a customer in the case of the SMP
- name: X-HTM-ROLE-HEADER
in: header
schema:
type: string
example: Customer
required: false
description: The role of the HTM employee in the case of the SMP
- name: notificationSubscriptionId
in: path
schema:
type: string
format: uuid
example: e112f26e-37fa-4bde-8def-9977cd1d50ae
required: true
description: The id of the notificationSubscription you want to update
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
Update a notificationSubscription to inactive:
value: { "isActive": False }
Update a notificationSubscription to active:
value: { "isActive": True }
responses:
"200":
description: OK
content:
application/json:
examples:
Update a notificationSubscription to inactive:
summary: Return the updated inactive notification
value:
{
"notificationSubscriptionId": "e112f26e-37fa-4bde-8def-9977cd1d50ae",
"notificationCategory":
{
"notificationCategoryId": 2,
"name": "Nieuwsbrief aanmelding",
},
"isActive": False,
}
Update a notificationSubscription to active:
summary: Return the updated active notification
value:
{
"notificationSubscriptionId": "e112f26e-37fa-4bde-8def-9977cd1d50ae",
"notificationCategory":
{
"notificationCategoryId": 2,
"name": "Nieuwsbrief aanmelding",
},
"isActive": True,
}
"405":
description: Method not allowed,wanneer het account emailadres niet geverifieerd is.
content:
application/json:
example:
{
"type": "https://api.integratielaag.nl/abt/touchpoint/2.0/notifications",
"title": "Methode niet toegestaan",
"detail": "",
"instance": "555d00b5-bc3f-4591-949b-479e76d49ea7",
"errors":
[
{
"code": "405",
"detail": null,
"path": null,
"parameter": null,
},
],
}
components:
schemas:
unavailable:
type: object

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,888 @@
openapi: 3.0.1
info:
title: ABTCustomerReference
version: '1.0'
servers:
- url: https://services.acc.api.htm.nl/abt/customerreference/1.0
security:
- default: []
tags:
- name: ABTCustomerReference
paths:
/directdebitmandatetype:
get:
tags:
- ABTCustomerReference
summary: List of direct debit mandate types
description: gives list of direct debit mandate types
parameters: []
responses:
'200':
description: Successful retrieved list of direct debit mandate types
content:
application/json:
schema:
$ref: '#/components/schemas/directDebitMandateTypes'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/phonetype:
get:
tags:
- ABTCustomerReference
summary: List of phone types
description: gives list of phone types
parameters: []
responses:
'200':
description: Successful retrieved list of phoneTypes
content:
application/json:
schema:
$ref: '#/components/schemas/phoneTypes'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
post:
tags:
- ABTCustomerReference
summary: Create a phone type
description: Create a phone type with a specific value
parameters: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/phoneType'
required: true
responses:
'201':
description: Successful created a new phone type
content:
application/json:
schema:
type: object
properties:
id:
type: integer
example: 1
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/phonetype/{phoneTypeId}:
put:
tags:
- ABTCustomerReference
summary: Update a phone type
description: Update an existing phone type with a specific value
parameters:
- name: phoneTypeId
in: path
required: true
style: simple
explode: false
schema:
type: integer
format: integer
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/phoneType'
required: true
responses:
'202':
description: Successful updated an existing a phone type
content:
application/json:
schema:
type: object
properties:
id:
type: integer
example: 1
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
delete:
tags:
- ABTCustomerReference
summary: Remove a phone type
description: Remove an existing phone type with a specific value
parameters:
- name: phoneTypeId
in: path
required: true
style: simple
explode: false
schema:
type: integer
format: integer
responses:
'202':
description: Successful removed a phone type
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
oneOf:
- $ref: '#/components/schemas/404ResponseId'
- $ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/addresstype:
get:
tags:
- ABTCustomerReference
summary: List of address types
description: gives list of address types
parameters: []
responses:
'200':
description: Successful retrieved list of addressTypes
content:
application/json:
schema:
$ref: '#/components/schemas/addressTypes'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/customerstatus:
get:
tags:
- ABTCustomerReference
summary: List of customer status
description: gives list of customer status
parameters: []
responses:
'200':
description: Successful retrieved list of customer status
content:
application/json:
schema:
$ref: '#/components/schemas/customerStatus'
example:
Entries:
- customerStatusId: 1
name: Inactive
- customerStatusId: 2
name: Active
- customerStatusId: 3
name: Blocked
- customerStatusId: 4
name: Frozen
- customerStatusId: 5
name: Cleared
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/tokentype:
get:
tags:
- ABTCustomerReference
summary: List of token types
description: gives list of token types
parameters: []
responses:
'200':
description: Successful retrieved list of customer status
content:
application/json:
schema:
$ref: '#/components/schemas/tokenType'
example:
Entries:
- tokenTypeId: 1
name: Debit card
- tokenTypeId: 2
name: Credit card
- tokenTypeId: 3
name: OVPas physical
- tokenTypeId: 4
name: OVPas digital
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/customerreferences:
get:
tags:
- ABTCustomerReference
summary: List of all possible customer reference values
description: gives list of all possible customer reference values availbale
parameters: []
responses:
'200':
description: Successful retrieved list of all possible customer reference values
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/customerReferences'
example:
Entries:
phoneTypes:
- name: mobile
id: 1
- name: fixed line
id: 2
addressTypes:
- name: home
id: 1
- name: office
id: 2
customerStatuses:
- name: active
id: 1
- name: blocked
id: 2
- name: inactive
id: 3
- name: new
id: 4
tokenTypes:
- name: Debit card
id: 1
- name: Credit card
id: 2
- name: OVPas physical
id: 3
- name: OVPas digital
id: 4
directDebitMandateTypes:
- name: Paper Contract
id: 1
- name: PIN transaction
id: 2
tokenStatuses:
- name: Expired
id: 1
- name: Active
id: 2
- name: Replaced
id: 3
- name: Inactive
id: 4
- name: Suspended
id: 5
- name: Removed by customer
id: 6
debtorStatuses:
- name: Inactive
id: 1
- name: Active
id: 2
languages:
- id: 1
name: Nederlands
ietfCode: nl-Nl
iso639Code: nl
- id: 2
name: English
ietfCode: en-US
iso639Code: en
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/tokenstatus:
get:
tags:
- ABTCustomerReference
summary: List of all token status
description: gives list of all token statuses
parameters: []
responses:
'200':
description: Successful retrieved list of customer status
content:
application/json:
schema:
$ref: '#/components/schemas/language'
example:
Entries:
- tokenStatusId: 1
name: Expired
- tokenStatusId: 2
name: Active
- tokenStatusId: 3
name: Replaced
- tokenStatusId: 4
name: Inactive
- tokenStatusId: 5
name: Suspended
- tokenStatusId: 6
name: Removed by customer
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/language:
get:
tags:
- ABTCustomerReference
summary: List of all languages
description: gives list of all languages
parameters: []
responses:
'200':
description: Successful retrieved list of languages
content:
application/json:
schema:
$ref: '#/components/schemas/language'
example:
Entries:
- languageId: 1
name: Expired
ietfCode: nl-NL
iso639Code: nl
- languageId: 2
name: Expired
ietfCode: en-US
iso639Code: en
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
/debtorstatus:
get:
tags:
- ABTCustomerReference
summary: List of all debtorstatuses
description: gives list of all debtorstatuses
parameters: []
responses:
'200':
description: Successful retrieved list of debtorstatuses
content:
application/json:
schema:
$ref: '#/components/schemas/tokenStatus'
example:
Entries:
- debtorStatusId: 1
name: Inactive
- debtorStatusId: 2
name: Active
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
security:
- default: []
x-auth-type: Application & Application User
x-throttling-tier: Unlimited
components:
schemas:
directDebitMandateTypeList:
type: array
items:
properties:
directDebitMandateTypeId:
type: integer
example: 1
name:
type: string
example: name
directDebitMandateType:
properties:
name:
type: string
example: name
id:
type: integer
example: 1
directDebitMandateTypes:
type: object
properties:
Entries:
$ref: '#/components/schemas/directDebitMandateTypeList'
phoneType:
properties:
name:
type: string
example: name
phoneTypeIdList:
type: array
items:
properties:
phoneTypeId:
type: integer
example: 123
name:
type: string
example: name
phoneTypes:
type: object
properties:
Entries:
$ref: '#/components/schemas/phoneTypeIdList'
addressType:
properties:
name:
type: string
example: name
addressTypeIdList:
type: array
items:
properties:
addressTypeId:
type: integer
example: 123
name:
type: string
example: name
addressTypes:
type: object
properties:
Entries:
$ref: '#/components/schemas/addressTypeIdList'
customerStatuses:
type: object
properties:
Entries:
$ref: '#/components/schemas/customerStatusIdList'
customerStatusIdList:
type: array
items:
properties:
customerStatusId:
type: integer
name:
type: string
customerStatus:
properties:
name:
type: string
example: name
tokenTypes:
type: object
properties:
Entries:
$ref: '#/components/schemas/customerStatusIdList'
tokenTypeIdList:
type: array
items:
properties:
tokenTypeId:
type: integer
name:
type: string
tokenType:
properties:
name:
type: string
example: name
tokenStatuses:
type: object
properties:
Entries:
$ref: '#/components/schemas/customerStatusIdList'
tokenStatusIdList:
type: array
items:
properties:
tokenStatusId:
type: integer
name:
type: string
tokenStatus:
properties:
tokenStatusId:
type: integer
example: 1
name:
type: string
example: name
debtorStatus:
properties:
debtorStatusId:
type: integer
example: 1
name:
type: string
example: name
language:
properties:
languageId:
type: integer
example: 1
name:
type: string
example: name
ietfCode:
type: string
example: nl-NL
iso639Code:
type: string
example: nl
customerReferences:
type: object
properties:
Entries:
oneOf:
- $ref: '#/components/schemas/addressType'
- $ref: '#/components/schemas/phoneType'
- $ref: '#/components/schemas/customerStatus'
- $ref: '#/components/schemas/tokenType'
- $ref: '#/components/schemas/directDebitMandateType'
- $ref: '#/components/schemas/tokenStatus'
400Response:
type: object
properties:
code:
type: string
example: '400'
type:
type: string
message:
type: string
example: Bad Request
description:
type: string
example: '''2023-02-01 00:00:00'' is not a valid Datetime'
401Response:
type: object
properties:
code:
type: string
example: '900901'
type:
type: string
message:
type: string
example: Invalid Credentials
description:
type: string
example: >-
Invalid Credentials. Make sure you have provided the correct
security credentials
404Response:
type: object
properties:
code:
type: string
example: '404'
type:
type: string
example: Status report
message:
type: string
example: Not Found
description:
type: string
example: The requested resource is not available.
404ResponseId:
type: object
properties:
error:
type: string
example: 'No record found for id: 5'
500Response:
type: object
properties:
code:
type: string
example: '500'
type:
type: string
message:
type: string
example: Internal Server Error
description:
type: string
securitySchemes:
default:
type: oauth2
flows:
implicit:
authorizationUrl: https://services.dev.api.htm.nl/authorize
scopes: {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,381 +0,0 @@
openapi: 3.0.1
info:
title: ABTFikoReference
description: |-
CRUD APIs for FIKO reference data (based on the v1 model for FIKO, see [the FIKO v1 datamodel in Lucid](https://lucid.app/lucidchart/50c0ff9d-48ba-4ea9-8182-10bede07d3b1/edit?viewport_loc=145%2C-316%2C2782%2C1418%2C0_0&invitationId=inv_1cd35e35-77f5-4e31-87d6-32fd74400350)). This means that, for now, only GET endpoints on `TaxMetadata` and `ProductGroupMetadata` (already named `ProductMetadata` to avoid rework for v2) are available.
When the v2 model for FIKO is implemented (see [the FIKO v2 datamodel in Lucid](https://lucid.app/lucidchart/50c0ff9d-48ba-4ea9-8182-10bede07d3b1/edit?viewport_loc=-72%2C-954%2C2406%2C1226%2CUnjZp4g0O~CK&invitationId=inv_1cd35e35-77f5-4e31-87d6-32fd74400350)), POST/PUT/DELETE for these tables (as well as CRUD for additional tables) will become available, to support populating the reference tables with Unit4Financials data.
These are NOT functional API's to be published by the Service Engine, but are direct CRUD API's on top of the database.
version: '1.0'
servers:
- url: https://api.integratielaag.nl/abt/fikoreference/1.0
tags:
- name: ABTFikoReference CRUD v1
description: >-
CRUD APIs for FIKO reference data (based on the v1 model for FIKO, see [the FIKO v1 datamodel in Lucid](https://lucid.app/lucidchart/50c0ff9d-48ba-4ea9-8182-10bede07d3b1/edit?viewport_loc=145%2C-316%2C2782%2C1418%2C0_0&invitationId=inv_1cd35e35-77f5-4e31-87d6-32fd74400350)).
- name: ABTFikoReference CRUD v2
description: >-
CRUD APIs for FIKO reference data (based on the v2 model for FIKO, see [the FIKO v2 datamodel in Lucid](https://lucid.app/lucidchart/50c0ff9d-48ba-4ea9-8182-10bede07d3b1/edit?viewport_loc=-72%2C-954%2C2406%2C1226%2CUnjZp4g0O~CK&invitationId=inv_1cd35e35-77f5-4e31-87d6-32fd74400350)).
paths:
/taxmetadata:
get:
tags:
- ABTFikoReference CRUD v1
summary: Get a list of all possible values of the "TaxMetadata" reference table. Mainly used for populating dropdown lists (in PMT for example).
description: |-
Get a list of all possible values of the `TaxMetadata` reference table. Mainly used for populating dropdown lists (in PMT for example).\
The attributes `validFrom` and `validUntil` are not yet present in the FIKO v1 datamodel, but are already included in this resourcemodel; to prevent rework in the near future.\
For now, for `validFrom`, the value will always be returned as `2024-01-01T00:00:00.000+00:00` and for `validUntil` it will always be `null`.
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/TaxMetadataListResponse'
examples:
getListTaxMetadataSales:
summary: List containing three TaxMetadata entries, used for sales tax
value:
{
"Entries": [
{
"taxMetadataId": "61A148AF-6DCB-4BB6-9D3F-17A8B627F745",
"taxCode": "V21",
"taxPercentageAmount": 21,
"description": "BTW VERKOOP HOOG 21%",
"validFrom": "2024-01-01T00:00:00.000+00:00",
"validUntil": null
},
{
"taxMetadataId": "47C8972E-A730-4032-9BDA-AF0A5BCB2C85",
"taxCode": "V09",
"taxPercentageAmount": 9,
"description": "BTW VERKOOP LAAG 9%",
"validFrom": "2024-01-01T00:00:00.000+00:00",
"validUntil": null
},
{
"taxMetadataId": "AC20A838-C81B-4652-96EA-F6E79E696E9C",
"taxCode": "V0",
"taxPercentageAmount": 0,
"description": "BTW VERKOOP NUL",
"validFrom": "2024-01-01T00:00:00.000+00:00",
"validUntil": null
}
]
}
getListTaxMetadataSalesAndPurchase:
summary: List containing x TaxMetadata entries, used for sales and purchase tax
value:
{
"Entries": [
{
"taxMetadataId": "61A148AF-6DCB-4BB6-9D3F-17A8B627F745",
"taxCode": "V21",
"taxPercentageAmount": 21,
"description": "BTW VERKOOP HOOG 21%",
"validFrom": "2024-01-01T00:00:00.000+00:00",
"validUntil": null
},
{
"taxMetadataId": "47C8972E-A730-4032-9BDA-AF0A5BCB2C85",
"taxCode": "V09",
"taxPercentageAmount": 9,
"description": "BTW VERKOOP LAAG 9%",
"validFrom": "2024-01-01T00:00:00.000+00:00",
"validUntil": null
},
{
"taxMetadataId": "AC20A838-C81B-4652-96EA-F6E79E696E9C",
"taxCode": "V0",
"taxPercentageAmount": 0,
"description": "BTW VERKOOP NUL",
"validFrom": "2024-01-01T00:00:00.000+00:00",
"validUntil": null
},
{
"TBD": "TBD"
},
{
"TBD": "TBD"
},
{
"TBD": "TBD"
}
]
}
'400':
description: '400'
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: '401'
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: '404'
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: '500'
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
/productmetadata:
get:
tags:
- ABTFikoReference CRUD v1
summary: Get a list of all possible values of the "ProductMetadata" reference table. Mainly used for populating dropdown lists (in PMT for example).
description: |-
Get a list of all possible values of the `ProductGroupMetadata` (soon to be renamed to `ProductMetadata`) reference table. Mainly used for populating dropdown lists (in PMT for example).\
The name of the entity is `ProductGroupMetadata` in the FIKO v1 datamodel, but the resourcemodel already uses the name `ProductMetadata`, as will be the name from FIKO v2 onwards.\
This also applies to the attributes `productMetadataId` (still called `ProductGroupMetadataId` in FIKO v1), `productCode` (still called `productGroupCode` in FIKO v1) and `user` (present in FIKO v1, but removed in FIKO v2, so also in this resourcemodel).
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/ProductMetadataListResponse'
examples:
getListProductMetadata:
summary: List containing one ProductMetadata entry, used for testing purposes
value:
{
"Entries": [
{
"productMetadataId": "501B17EF-36C4-4039-B92C-6517969B464E",
"productCode": "PG001",
"department": "Electronics",
"costCenter": "CC101",
"costType": "TypeA",
"description": "Group for electronic products",
"documentCode": "DOC001",
"timestampUpdated": "2024-09-03T15:07:53.470+00:00",
"validFrom": "2024-08-01T00:00:00.000+00:00",
"validUntil": "2025-08-01T00:00:00.000+00:00"
}
],
}
'400':
description: '400'
content:
application/json:
schema:
$ref: '#/components/schemas/400Response'
'401':
description: '401'
content:
application/json:
schema:
$ref: '#/components/schemas/401Response'
'404':
description: '404'
content:
application/json:
schema:
$ref: '#/components/schemas/404Response'
'500':
description: '500'
content:
application/json:
schema:
$ref: '#/components/schemas/500Response'
components:
schemas:
TaxMetadataListResponse:
type: object
required:
- Entries
properties:
Entries:
type: array
items:
$ref: '#/components/schemas/TaxMetadataResponse'
ProductMetadataListResponse:
type: object
required:
- Entries
properties:
Entries:
type: array
items:
$ref: '#/components/schemas/ProductMetadataResponse'
TaxMetadataResponse:
type: object
required:
- taxMetadataId
- taxCode
- taxPercentageAmount
- validFrom
properties:
taxMetadataId:
type: string
format: uuid
example: 501B17EF-36C4-4039-B92C-6517969B464E
taxCode:
type: string
example: V09
taxPercentageAmount:
type: integer
example: 21
description:
type: string
example: BTW VERKOOP LAAG 9%
validFrom:
type: string
format: date-time-offset
example: '2024-09-03T10:01:34.000+00:00'
validUntil:
type: string
format: date-time-offset
example: '2024-09-03T10:01:34.000+00:00'
ProductMetadataResponse:
type: object
required:
- productMetadataId
- productCode
- department
- costCenter
- costType
- description
- documentCode
- timestampUpdated
- validFrom
properties:
productMetadataId:
type: string
format: uuid
example: 501B17EF-36C4-4039-B92C-6517969B464E
productCode:
type: string
description: Called "artikelnr" in U4F
example: TBD
department:
type: string
description: Called "element 1" in U4F
example: TBD
costCenter:
type: string
description: Called "element 3" in U4F
example: TBD
costType:
type: string
description: Called "element 2" in U4F
example: TBD
description:
type: string
example: TBD
documentCode:
type: string
example: TBD
timestampUpdated:
type: string
format: date-time-offset
example: '2024-09-03T10:01:34.000+00:00'
validFrom:
type: string
format: date-time-offset
example: '2024-09-03T10:01:34.000+00:00'
validUntil:
type: string
format: date-time-offset
example: '2024-09-03T10:01:34.000+00:00'
400Response:
type: object
properties:
code:
type: string
example: '400'
type:
type: string
message:
type: string
example: Bad Request
description:
type: string
example: '''2023-02-01 00:00:00'' is not a valid Datetime'
apiErrorCode:
type: string
example: htm.api.err.40xxx
401Response:
type: object
properties:
code:
type: string
example: '900901'
type:
type: string
message:
type: string
example: Invalid Credentials
description:
type: string
example: >-
Invalid Credentials. Make sure you have provided the correct
security credentials
apiErrorCode:
type: string
example: htm.api.err.40xxx
403Response:
type: object
properties:
code:
type: string
example: '900901'
type:
type: string
message:
type: string
example: Retailer not authorized
description:
type: string
example: The retailer is not allowed to access resource for requested
apiErrorCode:
type: string
example: htm.api.err.40xxx touchpoint
404Response:
type: object
properties:
code:
type: string
example: '404'
type:
type: string
example: Status report
message:
type: string
example: Not Found
description:
type: string
example: The requested resource is not available.
apiErrorCode:
type: string
example: htm.api.err.40xxx
500Response:
type: object
properties:
code:
type: string
example: '500'
type:
type: string
message:
type: string
example: Internal Server Error
description:
type: string
apiErrorCode:
type: string
example: htm.api.err.40xxx

View File

@ -0,0 +1,206 @@
openapi: 3.0.3
info:
title: Service Desk Card Reader API
version: 0.9.0
description: |-
This API enables that external systems (such as SOS) can operate on information from service desk card readers.
### 0.9.0
- First draft version
servers:
- url: /v1
paths:
/card-reader/token:
post:
tags:
- CardReader
summary: Register a token from the card
operationId: registerToken
description: |
Register a token from the card to the external system.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/TokenRegisterRequest"
responses:
"202":
description: Accepted
"400":
description: |-
Bad Request. Occurs when the readerId is unknown to the external system. A call to `/card-reader/registrations`,
followed by a `/card-reader/register` is needed in order to restore reader registrations.
/card-reader/register:
post:
tags:
- CardReader
summary: Register a reader that is connected to the Card Reader Interface
operationId: registerReader
description: |
Register a reader to the external system to receive a newly generated readerID.
**N.B.**: After the last reader has been registered, an initial `/card-reader/registrations` call must be sent.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ReaderRegisterRequest"
responses:
"200":
description: Registration was successful
content:
application/json:
schema:
$ref: "#/components/schemas/ReaderRegisterResponse"
"400":
description: Bad Request
/card-reader/unregister:
post:
tags:
- CardReader
summary: Unregister a reader from the external system
operationId: unregisterReader
description: |
Unregister a reader from the external system.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/ReaderUnregisterRequest"
responses:
"204":
description: Unregistration was successful
"400":
description: Bad Request
/card-reader/registrations:
post:
tags:
- CardReader
summary: Send a list of readers that should currently be registered
operationId: sendReaderRegistrations
description: |
Send a list of readers of which the Card Reader Interface believes are registered. This must be done periodically.
The period is determined by the timeout duration in the response.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RegistrationsRequest"
responses:
"200":
description: Reader registrations successfully received
content:
application/json:
schema:
$ref: "#/components/schemas/RegistrationsResponse"
components:
schemas:
TokenRegisterRequest:
description: Request containing token information read using the card reader
type: object
properties:
readerId:
$ref: "#/components/schemas/ReaderId"
xBot:
type: string
format: uuid
description: The unique identifier of the token.
required:
- readerId
- xBot
ReaderRegisterRequest:
description: Request containing card reader information for one or more readers to be be registered
type: object
properties:
readerIdQuantity:
type: integer
default: 1
minimum: 1
cardReaderInterfaceId:
$ref: "#/components/schemas/cardReaderInterfaceId"
locationName:
$ref: "#/components/schemas/LocationName"
required:
- cardReaderInterfaceId
- locationName
- readerIdQuantity
ReaderRegisterResponse:
description: Response containing one or more readerIds for the registered reader(s)
type: object
properties:
readerIds:
type: array
items:
$ref: "#/components/schemas/ReaderId"
required:
- readerIds
ReaderUnregisterRequest:
description: Request containing the readerId to unregister
type: object
properties:
cardReaderInterfaceId:
$ref: "#/components/schemas/cardReaderInterfaceId"
locationName:
$ref: "#/components/schemas/LocationName"
readerId:
$ref: "#/components/schemas/ReaderId"
required:
- readerId
RegistrationsRequest:
description: Request containing a list of readerId of which the Card Reader Interface believes are registered.
type: object
properties:
cardReaderInterfaceId:
$ref: "#/components/schemas/cardReaderInterfaceId"
locationName:
$ref: "#/components/schemas/LocationName"
readerIds:
type: array
items:
$ref: "#/components/schemas/ReaderId"
required:
- cardReaderInterfaceId
- locationName
- readerIds
RegistrationsResponse:
description: Response with actionable information for the Card Reader Interface.
type: object
properties:
nextCallTimeout:
type: integer
description: |
Timeout duration in seconds BEFORE which the next `/card-reader/registrations` call should happen.
Failure to send a call before this timeout will result in automatic unregistration of all readers associated to this Card Read Interface.
The external systems must maintain a grace period on reception of the next call.
The Card Read Interface must start sending the next call on or before the timeout (grace period not needed).
readerIds:
type: array
items:
$ref: "#/components/schemas/ReaderId"
description: |
A list of readerIds that are registered to the external system. This mean all readerIds that readers with
readerIds missing from this list must be reregistered using `/card-reader/register`.
required:
- nextCallTimeout
- readerIds
cardReaderInterfaceId:
type: string
description: Each Card Reader Interface has a unique cardReaderInterfaceId. Identifier for the Card Reader Interface to which one or more readers are connected.
LocationName:
type: string
description: Name of the location of the reader. A location can have one ore more Card Reader Interfaces (cardReaderInterfaceIds)
ReaderId:
type: string
description: Unique identifier generated by the external system. Should be displayed on the screen of the reader.

View File

@ -0,0 +1,110 @@
openapi: 3.0.1
info:
title: Integratielaag APIs for one time tokens for a HTM customer
description: >-
Integratielaag APIs for one time tokens for a HTM customer. So that the a customer can be redirected between touchpoints, and the source of the request can be validated. NOTE : this is only to validate the redirect and the source of the redirect, touchpoint needs to make another call to take over the entra session.
version: "1.0"
servers:
- url: https://api.integratielaag.nl/v1/touchpoint
tags:
- name: OneTimeTokens
description: >-
Service Engine APIs for HTM Customers. These are NOT the CRUD APIs to access raw data in the database.
To be used by touchpoints to get information about HTM customers.
paths:
/one-time-tokens:
post:
tags:
- OneTimeTokens
summary: Create a one time token, to be included in the redirect
description: |
Create a one time token, to be included in the redirect
parameters:
- name: Authorization
in: header
required: true
style: simple
explode: false
schema:
type: string
example: Bearer {WSO2 Token}
description: Fill in a valid WSO2 Token for the touchpoint
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/unavailable'
example:
{
"nonce": "randomNonce123",
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q..."
}
responses:
"201":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/oneTimeTokenResponse"
/one-time-tokens/validate:
post:
tags:
- OneTimeTokens
summary: Validate a received one time token
description: Validate a received one time token through the redirect, validates the source and validity of the token
parameters:
- name: Authorization
in: header
required: true
style: simple
explode: false
schema:
type: string
example: Bearer {WSO2 Token}
description: Fill in a valid WSO2 Token for the touchpoint
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/unavailable'
example:
{
"token": "handoff-xyz987"
}
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/unavailable"
examples:
logged in user:
summary: Logged in user
description: Logged in user
value:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q..."
}
user not logged in:
summary: User not logged in
description: User not logged in
value:
{}
"400":
description: Bad request
"401":
description: Not authorized
components:
schemas:
unavailable:
type: object
oneTimeTokenResponse:
type: object
properties:
token:
type: string
example: "handoff-xyz987"
expires_in:
type: integer
example: 120

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,760 @@
openapi: 3.0.1
info:
title: PadpReferenceApi
version: '1.0'
paths:
/poc/encrypt-decrypt-poc:
get:
tags:
- Encrypt/decrypt POC
summary: Encrypt/Decrypt POC
operationId: EncryptDecryptPoc
parameters:
- name: textToEncrypt
in: header
required: true
schema:
type: string
- name: encryptedEphemeralKey
in: query
required: true
schema:
type: string
responses:
'200':
description: OK
content:
text/plain:
schema:
type: string
/poc/encrypt-poc:
get:
tags:
- Encrypt/decrypt POC
summary: Encrypt POC
operationId: EncryptPoc
parameters:
- name: textToEncrypt
in: header
required: true
schema:
type: string
- name: encryptedEphemeralKey
in: query
required: true
schema:
type: string
responses:
'200':
description: OK
content:
text/plain:
schema:
type: string
/poc/decrypt-poc:
get:
tags:
- Encrypt/decrypt POC
summary: Decrypt POC
operationId: DecryptPoc
parameters:
- name: textToDecrypt
in: header
required: true
schema:
type: string
- name: encryptedEphemeralKey
in: query
required: true
schema:
type: string
responses:
'200':
description: OK
content:
text/plain:
schema:
type: string
/idp/b2b-access-token:
get:
tags:
- PADP Reference API
summary: API 1020 - Get B2B Access Token
description: Returns a client access token, needed for most other PADP APIs.
operationId: GetB2bAccessToken
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/B2bAccessToken'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/get-image-from-base64:
get:
tags:
- PADP Reference API
summary: Get rendered image from Base64 encoded String
operationId: GetImageFromBase64
parameters:
- name: base64String
in: header
required: true
schema:
type: string
responses:
'200':
description: OK
content:
image/jpeg:
schema:
$ref: '#/components/schemas/FileContentHttpResult'
/personal-data/{xtat}:
post:
tags:
- PADP Reference API
summary: API 1201 - Create Personal Data - First create an ephemeral key using API 1210!
description: First create an ephemeral key using API 1210!
operationId: CreatePersonalData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
- name: email
in: query
description: Email address to be used for OTP challenges
required: true
schema:
type: string
- name: name
in: query
description: Should be at least two words (first name and last name)
schema:
type: string
- name: birthDate
in: query
description: Should be a date between 1900-01-01 and now, in the format YYYY-MM-DD
schema:
type: string
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
photo:
type: string
description: Should be a JPG image, of max. 512KB and resolution between 520x520 and 720x720
format: binary
encoding:
photo:
style: form
responses:
'201':
description: Created
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
get:
tags:
- PADP Reference API
summary: API 1202 - Get Personal Data- First perform an OTP challenge using API 1206 and 1207!
description: First perform an OTP challenge using API 1206 and 1207!
operationId: GetPersonalData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/PersonalData'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
delete:
tags:
- PADP Reference API
summary: API 1204 - Delete Personal Data - First perform an OTP challenge using API 1206 and 1207!
description: First perform an OTP challenge using API 1206 and 1207!
operationId: DeletePersonalData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/DeletePersonalDataResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
put:
tags:
- PADP Reference API
summary: API 1205 - Update Personal Data - First perform an OTP challenge using API 1206 and 1207!
description: First perform an OTP challenge using API 1206 and 1207!Performs a complete replacement; empty request parameters will result in the corresponding PADP attribute being deleted.
operationId: UpdatePersonalData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
- name: skipUpdateCounter
in: query
required: true
schema:
type: boolean
- name: name
in: query
description: Should be at least two words (first name and last name)
schema:
type: string
- name: birthDate
in: query
description: Should be a date between 1900-01-01 and now, in the format YYYY-MM-DD
schema:
type: string
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
photo:
type: string
description: Should be a JPG image, of max. 512KB and resolution between 520x520 and 720x720
format: binary
encoding:
photo:
style: form
responses:
'200':
description: OK
/personal-data/{xtat}/decrypted:
get:
tags:
- PADP Reference API
summary: API 1202 - Get Personal Data AND decrypt response - First perform an OTP challenge using API 1206 and 1207!
description: First perform an OTP challenge using API 1206 and 1207!
operationId: GetDecryptedPersonalData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/DecryptedPersonalData'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/personal-data/{xtat}/generate-otp:
get:
tags:
- PADP Reference API
summary: API 1206 - Generate OTP
operationId: GenerateOtp
parameters:
- name: xtat
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/OtpResponse'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/personal-data/{xtat}/validate-otp:
get:
tags:
- PADP Reference API
summary: API 1207 - Validate OTP
operationId: ValidateOtp
parameters:
- name: xtat
in: path
required: true
schema:
type: string
- name: otp
in: query
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/UserAccessToken'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/personal-data/{xtat}/encrypted-update-init:
get:
tags:
- PADP Reference API
summary: API 1210 - Create Ephemeral Key
operationId: CreateEphemeralKey
parameters:
- name: xtat
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/EphemeralKey'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/personal-data/{xtat}/administrative-data:
get:
tags:
- PADP Reference API
summary: API 1211 - Get Administrative Data
operationId: GetAdministrativeData
parameters:
- name: xtat
in: path
required: true
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/AdministrativeData'
'400':
description: Bad Request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'404':
description: Not Found
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
'500':
description: Internal Server Error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
components:
schemas:
AdministrativeData:
type: object
properties:
name:
$ref: '#/components/schemas/AdministrativeDataElement'
photo:
$ref: '#/components/schemas/AdministrativeDataElement'
birthdate:
$ref: '#/components/schemas/AdministrativeDataElement'
additionalProperties: false
AdministrativeDataElement:
type: object
properties:
inaccuracyFlag:
type: boolean
inaccuracyFlagReason:
type: string
nullable: true
inaccuracyFlagCounter:
type: integer
format: int32
changeCounter:
type: integer
format: int32
maxUpdatesVerificationCount:
type: integer
format: int32
lastChangeDate:
type: string
format: date-time
isValidated:
type: boolean
additionalProperties: false
B2bAccessToken:
type: object
properties:
access_token:
type: string
nullable: true
expires_in:
type: integer
format: int32
refresh_expires_in:
type: integer
format: int32
refresh_token:
type: string
nullable: true
token_type:
type: string
nullable: true
not-before-policy:
type: integer
format: int32
scope:
type: string
nullable: true
BE_ID:
type: string
nullable: true
additionalProperties: false
ByteReadOnlyMemory:
type: object
properties:
length:
type: integer
format: int32
readOnly: true
isEmpty:
type: boolean
readOnly: true
span:
$ref: '#/components/schemas/ByteReadOnlySpan'
additionalProperties: false
ByteReadOnlySpan:
type: object
properties:
length:
type: integer
format: int32
readOnly: true
isEmpty:
type: boolean
readOnly: true
additionalProperties: false
Data:
type: object
properties:
name:
type: string
nullable: true
birthdate:
type: string
nullable: true
photo:
type: string
nullable: true
additionalProperties: false
DecryptedData:
type: object
properties:
decryptedName:
type: string
nullable: true
decryptedBirthdate:
type: string
nullable: true
decryptedPhoto:
type: string
description: Base64 encoded photo
format: byte
nullable: true
additionalProperties: false
DecryptedPersonalData:
type: object
properties:
decryptedData:
$ref: '#/components/schemas/DecryptedData'
encryptedData:
$ref: '#/components/schemas/PersonalData'
additionalProperties: false
DeletePersonalDataResponse:
type: object
properties:
deletedAttributes:
type: array
items:
type: string
nullable: true
additionalProperties: false
EntityTagHeaderValue:
type: object
properties:
tag:
$ref: '#/components/schemas/StringSegment'
isWeak:
type: boolean
readOnly: true
additionalProperties: false
EphemeralKey:
type: object
properties:
ephemeralKeyAlias:
type: string
nullable: true
encryptedEphemeralKey:
type: string
nullable: true
additionalProperties: false
Error:
type: object
properties:
code:
type: string
nullable: true
data:
type: array
items:
type: string
nullable: true
message:
type: string
nullable: true
additionalProperties: false
ErrorResponse:
type: object
properties:
errors:
type: array
items:
$ref: '#/components/schemas/Error'
nullable: true
exceptionClassName:
type: string
nullable: true
exceptionStackTrace:
type: string
nullable: true
additionalProperties: false
FileContentHttpResult:
type: object
properties:
contentType:
type: string
nullable: true
readOnly: true
fileDownloadName:
type: string
nullable: true
readOnly: true
lastModified:
type: string
format: date-time
nullable: true
readOnly: true
entityTag:
$ref: '#/components/schemas/EntityTagHeaderValue'
enableRangeProcessing:
type: boolean
readOnly: true
fileLength:
type: integer
format: int64
nullable: true
readOnly: true
fileContents:
$ref: '#/components/schemas/ByteReadOnlyMemory'
additionalProperties: false
Metadata:
type: object
properties:
encryptedEphemeralKey:
type: string
nullable: true
additionalProperties: false
OtpResponse:
type: object
properties:
maskedEmailAddress:
type: string
nullable: true
additionalProperties: false
PersonalData:
type: object
properties:
metadata:
$ref: '#/components/schemas/Metadata'
data:
$ref: '#/components/schemas/Data'
additionalProperties: false
StringSegment:
type: object
properties:
buffer:
type: string
nullable: true
offset:
type: integer
format: int32
readOnly: true
length:
type: integer
format: int32
readOnly: true
value:
type: string
nullable: true
readOnly: true
hasValue:
type: boolean
readOnly: true
additionalProperties: false
UserAccessToken:
type: object
properties:
accessToken:
type: string
nullable: true
additionalProperties: false

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,593 @@
openapi: "3.0.3"
info:
title: Twilio SendGrid v3 API
description: >-
The Twilio SendGrid v3 API provides a simple, intuitive RESTful-like
interface for sending email at scale, monitoring email engagement data
programmatically, managing account settings, and more. This OpenAPI
representation of the Twilio SendGrid v3 API allows you to generate helper
libraries (in addition to the libraries officially released by Twilio
SendGrid) and build mock servers for testing.
termsOfService: https://www.twilio.com/legal/tos
contact:
name: Twilio SendGrid Support
url: https://support.sendgrid.com/hc/en-us
license:
name: MIT
url: https://github.com/sendgrid/sendgrid-oai/blob/main/LICENSE
version: 1.8.1
servers:
- url: https://https://services.acc.api.htm.nl/sendgrid
description: The Integration Layer SendGrid API integration (Acceptance).
paths:
/v3/mail/send:
post:
operationId: POST_mail-send
summary: v3 Mail Send
tags:
- Mail Send
description: |-
The Mail Send endpoint allows you to send email over SendGrid's v3 Web API, the most recent version of our API. If you are looking for documentation about the v2 Mail Send endpoint, see our [v2 API Reference](https://sendgrid.com/docs/API_Reference/Web_API/mail.html).
## Helper Libraries
Twilio SendGrid provides libraries to help you quickly and easily integrate with the v3 Web API in 7 different languages:
* [C#](https://github.com/sendgrid/sendgrid-csharp)
* [Go](https://github.com/sendgrid/sendgrid-go)
* [Java](https://github.com/sendgrid/sendgrid-java)
* [Node JS](https://github.com/sendgrid/sendgrid-nodejs)
* [PHP](https://github.com/sendgrid/sendgrid-php)
* [Python](https://github.com/sendgrid/sendgrid-python)
* [Ruby](https://github.com/sendgrid/sendgrid-ruby)
## Dynamic Transactional Templates and Handlebars
In order to send a dynamic template, specify the template ID with the `template_id` parameter.
To specify handlebar substitutions, define your substitutions in the request JSON with this syntax:
```
"dynamic_template_data": {
"guest": "Jane Doe",
"partysize": "4",
"english": true,
"date": "April 1st, 2021"
}
```
For more information about Dynamic Transactional Templates and Handlebars, see our documentation and reference pages.
* [How to send an email with Dynamic Transactional Templates
](https://sendgrid.com/docs/ui/sending-email/how-to-send-an-email-with-dynamic-transactional-templates/)
* [Using Handlebars](https://sendgrid.com/docs/for-developers/sending-email/using-handlebars/)
## Mail Body Compression
Mail body compression is available to some high volume accounts. Talk to your CSM if you are interested in this functionality. Mail body compression works by setting up a JSON payload as defined on this page, then compressing it with gzip (the gzip file can be no more than 30mb).
To use mail body compression:
1. Add a `Content-Encoding` header, with a value of `gzip`.
a. `Content-Encoding: gzip`
2. Send the gzip as a data-binary.
a. `--data-binary '@data.json.gz'
`
## Multiple Reply-To Emails
Using `reply_to_list` allows senders to include more than one recipient email address to receive reply and/or bounce messages from the recipient of the email.
### Usage Considerations
* `reply_to` is mutually exclusive with `reply_to_list`. If both are used, then the API call will be rejected.
* The `reply_to_list` object, when used, must at least have an email parameter and may also contain a name parameter.
* Each email address in the `reply_to_list` should be unique.
* There is a limit of 1000 `reply_to_list` emails per mail/send request.
* In SMTP calls, we will omit any invalid emails.
### Possible 400 Error Messages
* `reply_to` is mutually exclusive with `reply_to_list`.
* The `reply_to_list` object, when used, must at least have an email parameter and may also contain a name parameter.
* Each email address in the `reply_to_list` should be unique.
* There is a limit of X `reply_to` emails per mail/send request.
* The `reply_to_list` email does not contain a valid address.
* The `reply_to_list` email exceeds the maximum total length of X characters.
* The `reply_to_list` email parameter is required.
requestBody:
content:
application/json:
schema:
type: object
properties:
personalizations:
type: array
description: An array of messages and their metadata. Each object within personalizations can be thought of as an envelope - it defines who should receive an individual message and how that message should be handled. See our [Personalizations documentation](https://sendgrid.com/docs/for-developers/sending-email/personalizations/) for examples.
uniqueItems: false
maxItems: 1000
items:
type: object
properties:
from:
$ref: "#/components/schemas/from_email_object"
to:
$ref: "#/components/schemas/to_email_array"
cc:
type: array
description: An array of recipients who will receive a copy of your email. Each object in this array must contain the recipient's email address. Each object in the array may optionally contain the recipient's name.
maxItems: 1000
items:
$ref: "#/components/schemas/cc_bcc_email_object"
bcc:
type: array
description: An array of recipients who will receive a blind carbon copy of your email. Each object in this array must contain the recipient's email address. Each object in the array may optionally contain the recipient's name.
maxItems: 1000
items:
$ref: "#/components/schemas/cc_bcc_email_object"
subject:
type: string
description: The subject of your email. See character length requirements according to [RFC 2822](http://stackoverflow.com/questions/1592291/what-is-the-email-subject-length-limit#answer-1592310).
minLength: 1
headers:
type: object
description: 'A collection of JSON key/value pairs allowing you to specify handling instructions for your email. You may not overwrite the following headers: `x-sg-id`, `x-sg-eid`, `received`, `dkim-signature`, `Content-Type`, `Content-Transfer-Encoding`, `To`, `From`, `Subject`, `Reply-To`, `CC`, `BCC`'
substitutions:
type: object
description: Substitutions allow you to insert data without using Dynamic Transactional Templates. This field should **not** be used in combination with a Dynamic Transactional Template, which can be identified by a `template_id` starting with `d-`. This field is a collection of key/value pairs following the pattern "substitution_tag":"value to substitute". The key/value pairs must be strings. These substitutions will apply to the text and html content of the body of your email, in addition to the `subject` and `reply-to` parameters. The total collective size of your substitutions may not exceed 10,000 bytes per personalization object.
maxProperties: 10000
dynamic_template_data:
type: object
description: Dynamic template data is available using Handlebars syntax in Dynamic Transactional Templates. This field should be used in combination with a Dynamic Transactional Template, which can be identified by a `template_id` starting with `d-`. This field is a collection of key/value pairs following the pattern "variable_name":"value to insert".
custom_args:
type: object
description: Values that are specific to this personalization that will be carried along with the email and its activity data. Substitutions will not be made on custom arguments, so any string that is entered into this parameter will be assumed to be the custom argument that you would like to be used. This field may not exceed 10,000 bytes.
maxProperties: 10000
send_at:
type: integer
description: A unix timestamp allowing you to specify when your email should be delivered. Scheduling delivery more than 72 hours in advance is forbidden.
required:
- to
from:
$ref: "#/components/schemas/from_email_object"
reply_to:
$ref: "#/components/schemas/reply_to_email_object"
reply_to_list:
type: array
description: An array of recipients who will receive replies and/or bounces. Each object in this array must contain the recipient's email address. Each object in the array may optionally contain the recipient's name. You can either choose to use “reply_to” field or “reply_to_list” but not both.
uniqueItems: true
maxItems: 1000
items:
type: object
properties:
email:
type: string
description: The email address where any replies or bounces will be returned.
format: email
name:
type: string
description: A name or title associated with the `reply_to_list` email address.
required:
- email
subject:
type: string
description: The global or 'message level' subject of your email. This may be overridden by subject lines set in personalizations.
minLength: 1
content:
type: array
description: An array where you can specify the content of your email. You can include multiple [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) of content, but you must specify at least one MIME type. To include more than one MIME type, add another object to the array containing the `type` and `value` parameters.
items:
type: object
properties:
type:
type: string
description: The MIME type of the content you are including in your email (e.g., `“text/plain”` or `“text/html”`).
minLength: 1
value:
type: string
description: The actual content of the specified MIME type that you are including in your email.
minLength: 1
required:
- type
- value
attachments:
type: array
description: An array of objects where you can specify any attachments you want to include.
items:
type: object
properties:
content:
type: string
description: The Base64 encoded content of the attachment.
minLength: 1
type:
type: string
description: The MIME type of the content you are attaching (e.g., `“text/plain”` or `“text/html”`).
minLength: 1
filename:
type: string
description: The attachment's filename.
disposition:
type: string
default: attachment
description: The attachment's content-disposition, specifying how you would like the attachment to be displayed. For example, `“inline”` results in the attached file are displayed automatically within the message while `“attachment”` results in the attached file require some action to be taken before it is displayed, such as opening or downloading the file.
enum:
- inline
- attachment
content_id:
type: string
description: The attachment's content ID. This is used when the disposition is set to `“inline”` and the attachment is an image, allowing the file to be displayed within the body of your email.
required:
- content
- filename
template_id:
type: string
description: An email template ID. A template that contains a subject and content — either text or html — will override any subject and content values specified at the personalizations or message level.
headers:
description: An object containing key/value pairs of header names and the value to substitute for them. The key/value pairs must be strings. You must ensure these are properly encoded if they contain unicode characters. These headers cannot be one of the reserved headers.
type: object
categories:
type: array
description: 'An array of category names for this message. Each category name may not exceed 255 characters. '
uniqueItems: true
maxItems: 10
items:
type: string
maxLength: 255
custom_args:
description: Values that are specific to the entire send that will be carried along with the email and its activity data. Key/value pairs must be strings. Substitutions will not be made on custom arguments, so any string that is entered into this parameter will be assumed to be the custom argument that you would like to be used. This parameter is overridden by `custom_args` set at the personalizations level. Total `custom_args` size may not exceed 10,000 bytes.
type: string
send_at:
type: integer
description: A unix timestamp allowing you to specify when you want your email to be delivered. This may be overridden by the `send_at` parameter set at the personalizations level. Delivery cannot be scheduled more than 72 hours in advance. If you have the flexibility, it's better to schedule mail for off-peak times. Most emails are scheduled and sent at the top of the hour or half hour. Scheduling email to avoid peak times — for example, scheduling at 10:53 — can result in lower deferral rates due to the reduced traffic during off-peak times.
batch_id:
type: string
description: An ID representing a batch of emails to be sent at the same time. Including a `batch_id` in your request allows you include this email in that batch. It also enables you to cancel or pause the delivery of that batch. For more information, see the [Cancel Scheduled Sends API](https://sendgrid.com/docs/api-reference/).
asm:
type: object
description: An object allowing you to specify how to handle unsubscribes.
properties:
group_id:
type: integer
description: The unsubscribe group to associate with this email.
groups_to_display:
type: array
description: An array containing the unsubscribe groups that you would like to be displayed on the unsubscribe preferences page.
maxItems: 25
items:
type: integer
required:
- group_id
ip_pool_name:
type: string
description: The IP Pool that you would like to send this email from.
minLength: 2
maxLength: 64
mail_settings:
type: object
description: A collection of different mail settings that you can use to specify how you would like this email to be handled.
properties:
bypass_list_management:
type: object
description: Allows you to bypass all unsubscribe groups and suppressions to ensure that the email is delivered to every single recipient. This should only be used in emergencies when it is absolutely necessary that every recipient receives your email. This filter cannot be combined with any other bypass filters. See our [documentation](https://sendgrid.com/docs/ui/sending-email/index-suppressions/#bypass-suppressions) for more about bypass filters.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
bypass_spam_management:
type: object
description: Allows you to bypass the spam report list to ensure that the email is delivered to recipients. Bounce and unsubscribe lists will still be checked; addresses on these other lists will not receive the message. This filter cannot be combined with the `bypass_list_management` filter. See our [documentation](https://sendgrid.com/docs/ui/sending-email/index-suppressions/#bypass-suppressions) for more about bypass filters.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
bypass_bounce_management:
type: object
description: Allows you to bypass the bounce list to ensure that the email is delivered to recipients. Spam report and unsubscribe lists will still be checked; addresses on these other lists will not receive the message. This filter cannot be combined with the `bypass_list_management` filter. See our [documentation](https://sendgrid.com/docs/ui/sending-email/index-suppressions/#bypass-suppressions) for more about bypass filters.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
bypass_unsubscribe_management:
type: object
description: Allows you to bypass the global unsubscribe list to ensure that the email is delivered to recipients. Bounce and spam report lists will still be checked; addresses on these other lists will not receive the message. This filter applies only to global unsubscribes and will not bypass group unsubscribes. This filter cannot be combined with the `bypass_list_management` filter. See our [documentation](https://sendgrid.com/docs/ui/sending-email/index-suppressions/#bypass-suppressions) for more about bypass filters.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
footer:
type: object
description: The default footer that you would like included on every email.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
text:
type: string
description: The plain text content of your footer.
html:
type: string
description: The HTML content of your footer.
sandbox_mode:
type: object
description: Sandbox Mode allows you to send a test email to ensure that your request body is valid and formatted correctly.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
tracking_settings:
type: object
description: Settings to determine how you would like to track the metrics of how your recipients interact with your email.
properties:
click_tracking:
type: object
description: Allows you to track if a recipient clicked a link in your email.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
enable_text:
type: boolean
description: Indicates if this setting should be included in the `text/plain` portion of your email.
open_tracking:
type: object
description: Allows you to track if the email was opened by including a single pixel image in the body of the content. When the pixel is loaded, Twilio SendGrid can log that the email was opened.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
substitution_tag:
type: string
description: Allows you to specify a substitution tag that you can insert in the body of your email at a location that you desire. This tag will be replaced by the open tracking pixel.
subscription_tracking:
type: object
description: Allows you to insert a subscription management link at the bottom of the text and HTML bodies of your email. If you would like to specify the location of the link within your email, you may use the `substitution_tag`.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
text:
type: string
description: Text to be appended to the email with the subscription tracking link. You may control where the link is by using the tag <% %>
html:
type: string
description: HTML to be appended to the email with the subscription tracking link. You may control where the link is by using the tag <% %>
substitution_tag:
type: string
description: "A tag that will be replaced with the unsubscribe URL. for example: `[unsubscribe_url]`. If this parameter is used, it will override both the `text` and `html` parameters. The URL of the link will be placed at the substitution tag's location with no additional formatting."
ganalytics:
type: object
description: Allows you to enable tracking provided by Google Analytics.
properties:
enable:
type: boolean
description: Indicates if this setting is enabled.
utm_source:
type: string
description: Name of the referrer source. (e.g. Google, SomeDomain.com, or Marketing Email)
utm_medium:
type: string
description: Name of the marketing medium. (e.g. Email)
utm_term:
type: string
description: Used to identify any paid keywords.
utm_content:
type: string
description: Used to differentiate your campaign from advertisements.
utm_campaign:
type: string
description: The name of the campaign.
required:
- personalizations
- from
- subject
- content
example:
personalizations:
- to:
- email: john_doe@example.com
name: John Doe
- email: julia_doe@example.com
name: Julia Doe
cc:
- email: jane_doe@example.com
name: Jane Doe
bcc:
- email: james_doe@example.com
name: Jim Doe
- from:
email: sales@example.com
name: Example Sales Team
to:
- email: janice_doe@example.com
name: Janice Doe
bcc:
- email: jordan_doe@example.com
name: Jordan Doe
from:
email: orders@example.com
name: Example Order Confirmation
reply_to:
email: customer_service@example.com
name: Example Customer Service Team
subject: Your Example Order Confirmation
content:
- type: text/html
value: <p>Hello from Twilio SendGrid!</p><p>Sending with the email service trusted by developers and marketers for <strong>time-savings</strong>, <strong>scalability</strong>, and <strong>delivery expertise</strong>.</p><p>%open-track%</p>
attachments:
- content: PCFET0NUWVBFIGh0bWw+CjxodG1sIGxhbmc9ImVuIj4KCiAgICA8aGVhZD4KICAgICAgICA8bWV0YSBjaGFyc2V0PSJVVEYtOCI+CiAgICAgICAgPG1ldGEgaHR0cC1lcXVpdj0iWC1VQS1Db21wYXRpYmxlIiBjb250ZW50PSJJRT1lZGdlIj4KICAgICAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLCBpbml0aWFsLXNjYWxlPTEuMCI+CiAgICAgICAgPHRpdGxlPkRvY3VtZW50PC90aXRsZT4KICAgIDwvaGVhZD4KCiAgICA8Ym9keT4KCiAgICA8L2JvZHk+Cgo8L2h0bWw+Cg==
filename: index.html
type: text/html
disposition: attachment
categories:
- cake
- pie
- baking
send_at: 1617260400
batch_id: AsdFgHjklQweRTYuIopzXcVBNm0aSDfGHjklmZcVbNMqWert1znmOP2asDFjkl
asm:
group_id: 12345
groups_to_display:
- 12345
ip_pool_name: transactional email
mail_settings:
bypass_list_management:
enable: false
footer:
enable: false
sandbox_mode:
enable: false
tracking_settings:
click_tracking:
enable: true
enable_text: false
open_tracking:
enable: true
substitution_tag: '%open-track%'
subscription_tracking:
enable: false
responses:
'202':
description: ''
'400':
description: ''
content:
application/json:
schema:
$ref: "#/components/schemas/global_error_response_schema"
'401':
description: ''
content:
application/json:
schema:
$ref: "#/components/schemas/global_error_response_schema"
'403':
description: ''
content:
application/json:
schema:
$ref: "#/components/schemas/global_error_response_schema"
'404':
description: ''
content:
application/json:
schema:
$ref: "#/components/schemas/global_error_response_schema"
'413':
description: ''
content:
application/json:
schema:
$ref: "#/components/schemas/global_error_response_schema"
'500':
description: ''
content:
application/json:
schema:
$ref: "#/components/schemas/global_error_response_schema"
security:
- Authorization: []
components:
securitySchemes:
Authorization:
type: http
scheme: bearer
bearerFormat: JWT
description: >-
The API key used to authenticate with the SendGrid v3 API. You can find
your API key in the [Twilio SendGrid UI](https://app.sendgrid.com/settings/api_keys).
For more information, see our [API Key documentation](https://sendgrid.com/docs/ui/account-and-settings/api-keys/).
schemas:
from_email_object:
title: From Email Object
type: object
properties:
email:
type: string
format: email
description: The 'From' email address used to deliver the message. This address should be a verified sender in your Twilio SendGrid account.
name:
type: string
description: A name or title associated with the sending email address.
required:
- email
example:
email: jane_doe@example.com
name: Jane Doe
to_email_array:
title: To Email Array
type: array
items:
type: object
properties:
email:
type: string
format: email
description: The intended recipient's email address.
name:
type: string
description: The intended recipient's name.
required:
- email
example:
- email: john_doe@example.com
name: John Doe
cc_bcc_email_object:
title: CC BCC Email Object
type: object
properties:
email:
type: string
format: email
description: The intended recipient's email address.
name:
type: string
description: The intended recipient's name.
required:
- email
example:
email: jane_doe@example.com
name: Jane Doe
reply_to_email_object:
title: Reply_to Email Object
type: object
properties:
email:
type: string
format: email
description: The email address where any replies or bounces will be returned.
name:
type: string
description: A name or title associated with the `reply_to` email address.
required:
- email
example:
email: jane_doe@example.com
name: Jane Doe
global_error_response_schema:
title: Global Error Response Schema
type: object
properties:
errors:
type: array
items:
type: object
properties:
message:
type: string
description: the error message
field:
description: the field that generated the error
nullable: true
type: string
help:
type: object
description: helper text or docs for troubleshooting
required:
- message
id:
type: string
example:
errors:
- field: field_name
message: error message

View File

@ -0,0 +1,159 @@
openapi: "3.0.3"
info:
title: ABT Service CRUD APIs
version: "1.0"
description: CRUD APIs for ABT Service processes.
servers:
- url: https://api.integratielaag.nl/v1/service
paths:
/tokenregisterrequests:
get:
summary: Get all token register requests.
description: Get all token register requests.
tags:
- NFC Reader
parameters:
- in: query
name: readerId
schema:
type: string
example: b14b0320-2b72-48bb-990b-b97a2d67f9df
explode: false
required: false
description: Filter on possible NFC reader ids.
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/TokenRegisterRequestsGetResponse"
examples:
Single TokenRegisterRequest:
summary: Single TokenRegisterRequest
value:
{
"tokenRegisterRequests":
[
{
"readerId": "b14b0320-2b72-48bb-990b-b97a2d67f9df",
"xBot": "4bfaede2-a6c9-45dd-8a80-1f83a075a115",
"updated": "2025-07-02T15:01:00.000+00:00",
},
],
}
Multiple TokenRegisterRequests:
summary: Multiple TokenRegisterRequests
value:
{
"tokenRegisterRequests":
[
{
"readerId": "b14b0320-2b72-48bb-990b-b97a2d67f9df",
"xBot": "4bfaede2-a6c9-45dd-8a80-1f83a075a115",
"updated": "22025-07-02T15:01:00.000+00:00",
},
{
"readerId": "b4d8e43c-be21-472c-955b-a0c7c11b4bfb",
"xBot": "625bc66b-a5de-42fc-ba9e-fb02ada4a4ee",
"updated": "2025-07-02T13:37:07.000+00:00",
},
],
}
/tokenregisterrequests/{readerId}:
parameters:
- in: path
name: readerId
required: true
description: The NFC reader id.
schema:
type: string
example: b14b0320-2b72-48bb-990b-b97a2d67f9df
put:
summary: Insert or update token register request.
description: Insert or update token register request.
tags:
- NFC Reader
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/TokenRegisterRequestPutRequest"
example: { "xBot": "4bfaede2-a6c9-45dd-8a80-1f83a075a115" }
responses:
"200":
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/TokenRegisterRequestPutResponse"
example:
{
"readerId": "b14b0320-2b72-48bb-990b-b97a2d67f9df",
"xBot": "4bfaede2-a6c9-45dd-8a80-1f83a075a115",
"updated": "2025-07-02T15:01:00.000+00:00",
}
"201":
description: Created
content:
application/json:
schema:
$ref: "#/components/schemas/TokenRegisterRequestPutResponse"
example:
{
"readerId": "b14b0320-2b72-48bb-990b-b97a2d67f9df",
"xBot": "4bfaede2-a6c9-45dd-8a80-1f83a075a115",
"updated": "2025-07-02T15:01:00.000+00:00",
}
components:
securitySchemes:
bearerToken:
type: http
scheme: bearer
bearerFormat: JWT
schemas:
TokenRegisterRequestsGetResponse:
type: object
properties:
tokenRegisterRequests:
type: array
items:
$ref: "#/components/schemas/TokenRegisterRequest"
TokenRegisterRequestPutRequest:
type: object
properties:
xBot:
type: string
format: uuid
example: 4bfaede2-a6c9-45dd-8a80-1f83a075a115
nullable: false
description: The xBOT id.
required:
- xBot
TokenRegisterRequestPutResponse:
$ref: "#/components/schemas/TokenRegisterRequest"
TokenRegisterRequest:
type: object
properties:
readerId:
type: string
example: b14b0320-2b72-48bb-990b-b97a2d67f9df
nullable: false
description: The NFC reader id.
xBot:
type: string
format: uuid
example: 4bfaede2-a6c9-45dd-8a80-1f83a075a115
nullable: false
description: The xBOT id.
updated:
type: string
format: date-time
example: "2025-07-02T15:01:00+00:00"
nullable: false
description: The date and time when the token register request was updated.
required:
- readerId
- xBot
- updated

View File

@ -0,0 +1,477 @@
openapi: 3.0.1
info:
title: TapConnect
description: >-
Welcome to the TapConnect Issuing API documentation. These pages describe the endpoints available within TapConnect. Please note that for historical reasons, Date/times are always in the "Europe/Amsterdam" timezone. The endpoints in this document are grouped as follows:
- **Export endpoints**: Export related endpoints return information about events related to tickets that have been issued. This can be used for Business Intelligence purposes or for financial record keeping.
- **Product endpoints**: Product related endpoints return information about products that are available to you as a sales partner and the details of each of these products.
- **Ticket endpoints**: Ticket related endpoints allow you to manage tickets throughout their lifecycle. This includes ticket creation, retrieving ticket information, or retrieving the barcode for a ticket.
- **Journey endpoints**: Used to calculate the price of a journey and to issue a ticket for that journey using the external fare calculation engine.
For more information on TapConnect please visit [https://tapconnect.io](https://tapconnect.io) or [https://documentation.tapconnect.io](https://documentation.tapconnect.io).
version: '1.0'
servers:
- url: https://services.acc.api.htm.nl/tapconnect/1.0
tags:
- name: Export
description: >-
Export data that can be used to generate reports about issued tickets
and related information
paths:
/v5/ticket-events-export:
get:
summary: Elastic Search ticket events export
description: "Exports ticket events data from Elastic Search.\n\nBoth parameters\
\ are a string, and they have to represent a date. Consider the list of valid\
\ formats below:\n1. 2021 - searches for all events in a year\n2. 2021-02\
\ - searches for all events in a month\n3. 2021-02-02 - searches for all events\
\ in a day\n4. 2021-02-02T12 - searches for all events in a specific hour\n\
5. 2021-02-02T12:00 - searches for all events in a specific minute\n6. 2021-02-02T12:00:00\
\ - searches for all events in a specific second\n\nIf an error occur, the\
\ last element returned will be a message with \"An error occurred on Elasticsearch\"\
\ and it \nmeans that not all the results are returned.\n_Keep in mind that\
\ the above timestamps would also be accepted as Zulu: 2021-02-02T11:00:00Z\
\ (winter time)_\n"
parameters:
- explode: true
in: query
name: start
required: true
description: The date to be considered as the interval starting date
schema:
example: 2021-02-01T00:00:00
type: string
style: form
- explode: true
in: query
name: end
required: true
description: The date to be considered as the interval ending date
schema:
example: 2021-02-02T00:00:00
type: string
style: form
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/v5_ticket_events_export_response'
description: Returns a JSON chunked array of ticket events exported from elastic search.
"400":
description: |
The request could not be validated. The request body or parameters contain incomplete or incorrect parameters. The body of the response will contain information about the problem.
"401":
description: |
Unauthorized call, you are not authorized to call this endpoint with the api key provided in the Authorization header. Please verify that your api key is correct and/or if you are authorized to call this endpoint.
"403":
description: |
Unauthorized call, you are not authorized to call this endpoint with the api key provided in the Authorization header. Please verify that your api key is correct and/or if you are authorized to call this endpoint.
"404":
description: |
The requested URL does not exist, or the requested object was not found.
"406":
description: |
The request was not accepted by the server. The body of the response will contain information about the problem.
tags:
- Export
components:
schemas:
v5_ticket_events_export_response:
type: array
items:
anyOf:
- $ref: '#/components/schemas/ActivateTicketEvent'
- $ref: '#/components/schemas/CreateBarcodeEvent'
- $ref: '#/components/schemas/CreateTicketEvent'
- $ref: '#/components/schemas/TapEvent'
- $ref: '#/components/schemas/InspectTicketEvent'
- $ref: '#/components/schemas/NotifyEvent'
ActivateTicketEvent:
properties:
eventId:
example: 1
type: number
eventType:
example: ACTIVATE_TICKET
type: string
occurredAt:
example: 2021-06-07T08:42:00.791992000Z
type: string
receivedAt:
example: 2021-06-07T08:42:00.791992000Z
type: string
timeToDie:
example: 2445836980
type: number
operators:
items:
example: HTM
type: string
type: array
createdBy:
example: HTM
type: string
definedBy:
example: HTM
type: string
ticketId:
example: hkbu3415fbidswd803nfdg7
type: string
validityStart:
example: 2021-06-06T22:00:00.000000000Z
type: string
validityEnd:
example: 2021-06-07T23:40:00.000000000Z
type: string
validityType:
example: FIXED
type: string
CreateBarcodeEvent:
properties:
eventId:
example: 2
type: number
eventType:
example: CREATE_BARCODE
type: string
occurredAt:
example: 2021-06-07T08:42:01.629279000Z
type: string
receivedAt:
example: 2021-06-07T08:42:01.629279000Z
type: string
timeToDie:
example: 2445836980
type: number
operators:
items:
example: HTM
type: string
type: array
createdBy:
example: HTM
type: string
definedBy:
example: HTM
type: string
ticketId:
example: 2huCpR99LHjGfiq8ZJoF
type: string
barcodeSignatureKeyId:
example: TCT07
type: string
barcodeValidityStart:
example: 2021-06-06T22:00:00.000000000Z
type: string
barcodeValidityEnd:
example: 2021-06-07T23:40:00.000000000Z
type: string
CreateTicketEvent:
properties:
eventId:
example: 0
type: number
eventType:
example: CREATE_TICKET
type: string
occurredAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
receivedAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
reportedAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
timeToDie:
example: 2445836980
type: number
operators:
items:
example: HTM
type: string
type: array
createdBy:
example: HTM
type: string
definedBy:
example: HTM
type: string
ticketId:
example: 344BEuHcFkEChOPm06sY
type: string
serviceId:
example: HTM-0987-7477-0993
type: string
productName:
example: HTM Kinder Dagkaart
type: string
productCode:
example: "303"
type: string
productValidityPeriodUnit:
example: "DAYS"
type: string
productValidityPeriod:
example: 1
type: number
lifespanStart:
example: 2021-06-07
type: string
lifespanEnd:
example: 2021-06-08
type: string
language:
example: NL
type: string
salesChannelId:
example: "9999"
type: string
salesChannelName:
example: HTM App
type: string
startStation:
example: Haarlem
type: string
endStation:
example: Leiden Centraal
type: string
barcodeType:
example: UIC
type: string
validityType:
example: FIXED
type: string
refundable:
example: true
type: boolean
priceInCents:
example: 150,
type: number
numberOfAdults:
example: 1
type: number
numberOfChildren:
example: 0
type: number
roundToBusinessDay:
example: true
type: boolean
modalities:
example: ["BUS", "TRAM"]
type: array
items:
example: BUS
type: string
TapEvent:
properties:
eventId:
example: 5
type: number
eventType:
example: TAP
type: string
occurredAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
receivedAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
timeToDie:
example: 2445836980
type: number
validationAction:
example: CHECK_OUT
type: string
validationResult:
example: Approved
type: string
tapId:
example: a9aea0ae-52de-42cd-a2f1-93b80d9af389
type: string
operators:
items:
example: HTM
type: string
type: array
createdBy:
example: HTM
type: string
definedBy:
example: HTM
type: string
ticketId:
example: hkbu3415fbidswd803nfdg7
type: string
modality:
example: BUS
type: string
line:
example: "25"
type: string
trip:
example: "240"
type: string
vehicle:
example: "1512"
type: string
deviceId:
example: "13513A"
type: string
deviceType:
example: VBS
type: string
lastStopId:
example: "3409"
type: string
lastStopName:
example: Gramsbergenlaan
type: string
nextStopId:
example: "3409"
type: string
nextStopName:
example: Gramsbergenlaan
type: string
location:
type: object
properties:
lat:
example: 52.00089453333333
type: number
lon:
example: 4.004570666666667
type: number
InspectTicketEvent:
properties:
eventId:
example: 3
type: number
eventType:
example: INSPECT_TICKET
type: string
occurredAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
receivedAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
timeToDie:
example: 2445836980
type: number
operators:
items:
example: HTM
type: string
type: array
createdBy:
example: HTM
type: string
definedBy:
example: HTM
type: string
ticketId:
example: uv1hzvrRd7Xd1Fs9vTxi
type: string
modality:
example: BUS
type: string
deviceId:
example: 6959bd00eaec8e68
type: string
deviceType:
example: IBS
type: string
validationResult:
example: Approved
type: string
NotifyEvent:
properties:
eventId:
example: 1185
type: number
eventType:
example: NOTIFY
type: string
occurredAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
receivedAt:
example: 2021-06-07T08:42:00.790992000Z
type: string
timeToDie:
example: 2445836980
type: number
tapId:
example: a9aea0ae-52de-42cd-a2f1-93b80d9af389
type: string
sequence:
example: 2
type: number
tapResponseTimeMillis:
example: 402
type: number
validationAction:
example: CHECK_OUT
type: string
validationMethod:
example: ONLINE
type: string
validationResult:
example: Approved
type: string
operators:
items:
example: HTM
type: string
type: array
createdBy:
example: HTM
type: string
definedBy:
example: HTM
type: string
modality:
example: TRAM
type: string
line:
example: "3"
type: string
trip:
example: "692"
type: string
vehicle:
example: "4058"
type: string
deviceId:
example: "13A886"
type: string
deviceType:
example: VBS
type: string
lastStopId:
example: "2005"
type: string
lastStopName:
example: Fahrenheitstraat
type: string
nextStopId:
example: "2011"
type: string
nextStopName:
example: Valkenbosplein
type: string
ticketId:
example: hkbu3415fbidswd803nfdg7
type: string
location:
type: object
properties:
lat:
example: 52.001300283333336
type: number
lon:
example: 4.004586633333333
type: number

View File

@ -4,7 +4,7 @@ info:
version: "1.0" version: "1.0"
description: CRUD APIs for ABT Utility tables. These are NOT the functional APIs from Service Engine. description: CRUD APIs for ABT Utility tables. These are NOT the functional APIs from Service Engine.
servers: servers:
- url: https://api.integratielaag.nl/v1 - url: https://services.acc.api.htm.nl/abt/abtutility/1.0
paths: paths:
/scheduledactions: /scheduledactions:
get: get:
@ -86,6 +86,20 @@ paths:
example: 65ad5520-4e62-41b7-89dd-a01be6cb78bf example: 65ad5520-4e62-41b7-89dd-a01be6cb78bf
required: false required: false
description: Pointer to executor of this action (e.g. the batch job). description: Pointer to executor of this action (e.g. the batch job).
- in: query
name: role
schema:
type: string
example: customer
required: false
description: Role of the user or process that initiated the action.
- in: query
name: user
schema:
type: string
example: 1255ab39-2f10-409a-bf61-38c07e1b8a9e
required: false
description: User that initiated the action. In case of a customer this is the customer id.
- in: query - in: query
name: resourceName name: resourceName
schema: schema:
@ -123,6 +137,8 @@ paths:
"created": "2024-07-02 15:01:00.000", "created": "2024-07-02 15:01:00.000",
"updated": "2024-07-02 15:01:00.000", "updated": "2024-07-02 15:01:00.000",
"correlationId": "fb4443c6-5a6a-47a3-adf0-db3dfc183399", "correlationId": "fb4443c6-5a6a-47a3-adf0-db3dfc183399",
"role": "customer",
"user": "1255ab39-2f10-409a-bf61-38c07e1b8a9e",
"scheduledActionResources": "scheduledActionResources":
[ [
{ {
@ -157,6 +173,8 @@ paths:
"created": "2024-07-02 15:01:00.000", "created": "2024-07-02 15:01:00.000",
"updated": "2024-07-02 15:01:00.000", "updated": "2024-07-02 15:01:00.000",
"correlationId": "fb4443c6-5a6a-47a3-adf0-db3dfc183399", "correlationId": "fb4443c6-5a6a-47a3-adf0-db3dfc183399",
"role": "customer",
"user": "1255ab39-2f10-409a-bf61-38c07e1b8a9e",
"scheduledActionResources": "scheduledActionResources":
[ [
{ {
@ -217,6 +235,8 @@ paths:
"created": "2024-07-02 15:01:00.000", "created": "2024-07-02 15:01:00.000",
"updated": "2024-07-02 15:01:00.000", "updated": "2024-07-02 15:01:00.000",
"correlationId": "fb4443c6-5a6a-47a3-adf0-db3dfc183399", "correlationId": "fb4443c6-5a6a-47a3-adf0-db3dfc183399",
"role": "customer",
"user": "1255ab39-2f10-409a-bf61-38c07e1b8a9e",
"scheduledActionResources": "scheduledActionResources":
[ [
{ {
@ -390,6 +410,12 @@ components:
type: string type: string
format: uuid format: uuid
example: 8699d72a-cf4d-4e6b-9e9c-549d837ca51f example: 8699d72a-cf4d-4e6b-9e9c-549d837ca51f
role:
type: string
example: customer
user:
type: string
example: 1255ab39-2f10-409a-bf61-38c07e1b8a9e
ScheduledActionType: ScheduledActionType:
type: object type: object
properties: properties:

View File

@ -0,0 +1,52 @@
// ==UserScript==
// @name gitea-add-swagger-button
// @namespace https://integratielaag.nl/
// @version 0.1.1
// @description Creates a button in Gitea to view Swagger
// @author bboterm
// @match https://git.integratielaag.nl/*.yaml
// @match https://git.integratielaag.nl/*.json
// @icon https://www.google.com/s2/favicons?sz=64&domain=gitea.com
// @grant none
// @updateURL https://git.integratielaag.nl/HTM/ovpay/raw/branch/develop/src/plugins/gitea-add-swagger-button.user.js
// @downloadURL https://git.integratielaag.nl/HTM/ovpay/raw/branch/develop/src/plugins/gitea-add-swagger-button.user.js
// ==/UserScript==
// @history 0.1.0 Initial release
// @history 0.1.1 Added support for YAML and JSON files
(function() {
'use strict';
// Set the base URL for the Swagger instance
const swaggerBaseURL = 'https://swagger.integratielaag.nl/?url=';
// Get the base URL from the current webpage
const gitBaseURL = window.location.origin;
// Replace 'parent-class-name' with the class name of the parent div
const parentClassName = 'file-actions';
// Replace 'child-class-name' with the class name of the child div
const childClassName = 'buttons';
const parentDiv = document.querySelector('div.file-actions');
if (parentDiv) {
const childDiv = parentDiv.querySelector('div.buttons');
if (childDiv) {
const firstATag = childDiv.querySelector('a');
if (firstATag) {
// Get the URL of the raw file
const hrefValue = firstATag.getAttribute('href');
// Create a string literal for the new Swagger button
const swaggerButton = `<a class="ui mini basic button" target="_blank" href="${swaggerBaseURL}${gitBaseURL}/${hrefValue}">Swagger</a>`;
// Add the Swagger button to the HTML
childDiv.innerHTML = swaggerButton + childDiv.innerHTML;
} else {
console.log('No <a> tag found inside the child div.');
}
} else {
console.log(`Child div with class '${childClassName}' not found.`);
}
} else {
console.log(`Parent div with class '${parentClassName}' not found.`);
}
})();

View File

@ -0,0 +1,65 @@
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:web="http://www.coda.com/efinance/schemas/inputext/input-14.0/webservice"
xmlns:tran="http://www.coda.com/efinance/schemas/transaction"
xmlns:flex="http://www.coda.com/common/schemas/flexifield"
xmlns:att="http://www.coda.com/common/schemas/attachment"
xmlns:inp="http://www.coda.com/efinance/schemas/inputext"
xmlns:mat="http://www.coda.com/efinance/schemas/matching"
xmlns:ass="http://www.coda.com/efinance/schemas/association">
<soapenv:Body>
<web:PostToBooksRequest>
<web:Transaction>
<tran:Header
xmlns:tran="http://www.coda.com/efinance/schemas/transaction">
<tran:Key>
<tran:CmpCode>1HTM</tran:CmpCode>
<tran:Code>OPBR-FIKO</tran:Code>
</tran:Key>
<tran:TimeStamp>0</tran:TimeStamp>
<tran:InputDate>2024-11-25T00:00:00.000Z</tran:InputDate>
<tran:Period>2024/7</tran:Period>
<tran:CurCode>EUR</tran:CurCode>
<tran:Date>2024-07-25T00:00:00.000Z</tran:Date>
<tran:OriginalCompany>1HTM</tran:OriginalCompany>
<tran:OriginalCode>OPBR-FIKO</tran:OriginalCode>
<tran:CompletionWorkflow>
<tran:CompletionStatus>wfl_no_completion</tran:CompletionStatus>
</tran:CompletionWorkflow>
<tran:SalesInvoiceStatus>salesinv_notyetinv</tran:SalesInvoiceStatus>
</tran:Header>
<tran:Lines
xmlns:tran="http://www.coda.com/efinance/schemas/transaction">
<tran:Line>
<tran:Number>1</tran:Number>
<tran:AccountCode>100.12400.D150000001</tran:AccountCode>
<tran:DocValue>100.00</tran:DocValue>
<tran:LineType>summary</tran:LineType>
<tran:LineSense>debit</tran:LineSense>
<tran:LineOrigin>dl_orig_defined</tran:LineOrigin>
<tran:Description>test</tran:Description>
<tran:ExtRef1>987654</tran:ExtRef1>
<tran:ExtRef2>test987654</tran:ExtRef2>
<tran:SEPAPaymentCategoryPurposeCode>none</tran:SEPAPaymentCategoryPurposeCode>
<tran:SEPAPaymentPurposeCode>none</tran:SEPAPaymentPurposeCode>
</tran:Line>
<tran:Line>
<tran:Number>2</tran:Number>
<tran:AccountCode>642.41236.609311</tran:AccountCode>
<tran:DocValue>100.00</tran:DocValue>
<tran:UserStatus/>
<tran:LineType>analysis</tran:LineType>
<tran:LineSense>credit</tran:LineSense>
<tran:LineOrigin>dl_orig_defined</tran:LineOrigin>
<tran:SEPAPaymentCategoryPurposeCode>none</tran:SEPAPaymentCategoryPurposeCode>
<tran:SEPAPaymentPurposeCode>none</tran:SEPAPaymentPurposeCode>
</tran:Line>
</tran:Lines>
</web:Transaction>
<web:PostData>
<web:Template>OPBR-FIKO</web:Template>
<web:DocumentWideData/>
</web:PostData>
</web:PostToBooksRequest>
</soapenv:Body>
</soapenv:Envelope>

View File

@ -0,0 +1,77 @@
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.coda.com/efinance/schemas/inputext/input-14.0/webservice" xmlns:tran="http://www.coda.com/efinance/schemas/transaction" xmlns:flex="http://www.coda.com/common/schemas/flexifield" xmlns:att="http://www.coda.com/common/schemas/attachment" xmlns:inp="http://www.coda.com/efinance/schemas/inputext" xmlns:mat="http://www.coda.com/efinance/schemas/matching" xmlns:ass="http://www.coda.com/efinance/schemas/association">
<soapenv:Header>
<web:Options/>
</soapenv:Header>
<soapenv:Body>
<web:PostRequest>
<web:PostOptions postto="intray" reportallerrors="1"/> <!-- postto staat nu naar het register (intray). Dit zou ik een live situatie moeten/kunnen worden aangepast naar de boeken (books) -->
<web:Transaction>
<tran:Header>
<tran:Key>
<tran:CmpCode>1HTM</tran:CmpCode> <!-- Unit4 Financials bedrijf -->
<tran:Code>VERK_FACTUUR</tran:Code> <!-- Documentcode -->
</tran:Key>
<tran:TimeStamp>0</tran:TimeStamp> <!-- Timestamp bij nieuwe transacties altijd 0 -->
<tran:Period>2024/5</tran:Period> <!-- Jaar en periode van boeken -->
<tran:CurCode>EUR</tran:CurCode> <!-- Valutacode -->
<tran:Date>2024-06-05T00:00:00.000Z</tran:Date> <!-- Documentdatum> -->
<tran:Description>DW12345</tran:Description> <!-- Omschrijving document -->
</tran:Header>
<tran:Lines>
<tran:Line>
<tran:Number>1</tran:Number> <!-- Regelnummer - 1 Debiteurenregel -->
<tran:AccountCode>1200.D001</tran:AccountCode> <!-- Boeken op elementcode, in dit geval alleen elementen op niveau 1 en 2 (gescheiden door een punt) -->
<tran:DocValue>121.00</tran:DocValue> <!-- Totaalbedrag debiteurenregel -->
<tran:LineType>summary</tran:LineType> <!-- Type regel, in het geval van een debiteurenregel is dit summary -->
<tran:LineSense>credit</tran:LineSense> <!-- Debet of Credit -->
<tran:LineOrigin>dl_orig_defined</tran:LineOrigin> <!-- Aangezien hier gebruik wordt gemaakt van het invoersjabloon FACTUUR_VER (zie regel 72) is dit een vooraf gedefinieerde regel ( dl_orig_defined) -->
<tran:Description>Nov 2020 Huur</tran:Description> <!-- Regelomschrijving -->
<tran:ExtRef1>DW12345</tran:ExtRef1> <!-- Externe referentie 1 -->
<tran:ExtRef2/> <!-- Externe referentie 2, nu niet gevuld -->
<tran:ExtRef3/> <!-- Externe referentie 3, nu niet gevuld, hieronder kunnen ook nog andere referenties worden opgenomen -->
<tran:DocSumTax>21.00</tran:DocSumTax> <!-- BTW-bedrag behorende bij debiteurenregel -->
<tran:TaxInclusive>false</tran:TaxInclusive> <!-- Inclusief of exclusief BTW -->
</tran:Line>
<tran:Line>
<tran:Number>2</tran:Number> <!-- Regelnummer - 1 Omzetregel -->
<tran:AccountCode>4300</tran:AccountCode> <!-- Boeken op elementcode, in dit geval alleen element op niveau 1 -->
<tran:DocValue>100.00</tran:DocValue> <!-- Totaalbedrag omzetregel -->
<tran:LineType>analysis</tran:LineType> <!-- Type regel, in het geval van een omzetregel is dit analyses (analyse) -->
<tran:LineSense>debit</tran:LineSense> <!-- Debet of Credit -->
<tran:LineOrigin>dl_orig_defined</tran:LineOrigin> <!-- Aangezien hier gebruik wordt gemaakt van het invoersjabloon FACTUUR_VER (zie regel 72) is dit een vooraf gedefinieerde regel ( dl_orig_defined) -->
<tran:Description>Voorschot Q1.</tran:Description> <!-- Regelomschrijving -->
<tran:ExtRef1>Ref. DW12345</tran:ExtRef1> <!-- Externe referentie 1 -->
<tran:ExtRef2/> <!-- Externe referentie 2, nu niet gevuld -->
<tran:ExtRef3/> <!-- Externe referentie 3, nu niet gevuld, hieronder kunnen ook nog andere referenties worden opgenomen -->
<tran:TaxInclusive>false</tran:TaxInclusive> <!-- Inclusief of exclusief BTW -->
<tran:Taxes>
<tran:Tax>
<tran:Code>21%</tran:Code> <!-- BTW-code -->
<tran:ShortName>21% BTW</tran:ShortName> <!-- Verkorte omschrijving BTW -->
<tran:Value>21.00</tran:Value> <!-- BTW-bedrag analyse regel -->
</tran:Tax>
</tran:Taxes>
</tran:Line>
<tran:Line>
<tran:Number>3</tran:Number> <!-- Regelnummer - 3 BTW-regel -->
<tran:AccountCode>1400</tran:AccountCode> <!-- Boeken op elementcode, in dit geval alleen element op niveau 1 -->
<tran:DocValue>21.00</tran:DocValue> <!-- BTW-bedrag -->
<tran:LineType>tax</tran:LineType> <!-- Type regel, in het geval van een BTW-regel is dit tax (BTW) -->
<tran:LineSense>debit</tran:LineSense> <!-- Debet of Credit -->
<tran:LineOrigin>dl_orig_gentax</tran:LineOrigin> <!-- Aangezien hier gebruik wordt gemaakt van het invoersjabloon FACTUUR_VER (zie regel 72) is dit een vooraf gedefinieerde regel ( dl_orig_gentax) -->
<tran:Description>Test DW</tran:Description> <!-- Regelomschrijving -->
<tran:ExtRef1/>
<tran:ExtRef2/>
<tran:ExtRef3/>
<tran:TaxLineCode>21%</tran:TaxLineCode> <!-- BTW-code -->
<tran:DocTaxTurnover>100.00</tran:DocTaxTurnover> <!-- Bedrag waar BTW over berekend -->
</tran:Line>
</tran:Lines>
</web:Transaction>
<web:PostData>
<inp:Template>FACTUUR_VER</inp:Template> <!-- Te gebruiken invoersjabloon -->
<inp:DocumentWideData/>
</web:PostData>
</web:PostRequest>
</soapenv:Body>
</soapenv:Envelope>