├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── comment-or-question---.md │ └── feature_request.md ├── LICENSE ├── Nutzungslizenz-SWP-API.docx └── Nutzungslizenz-SWP-API.pdf ├── README.md ├── api └── swp-nwp-api-v1-swagger.yaml └── documents ├── InterfaceRecommendationSIXeBill-1.0.docx ├── InterfaceRecommendationSIXeBill-1.0.pdf ├── InterfaceRecommendationSIXeBill-1.01.docx ├── InterfaceRecommendationSIXeBill-1.01.pdf ├── SchnittstellenempfehlungSIXeBill-1.0.docx ├── SchnittstellenempfehlungSIXeBill-1.0.pdf ├── SchnittstellenempfehlungSIXeBill-1.01.docx ├── SchnittstellenempfehlungSIXeBill-1.01.pdf ├── meeting-notes ├── 2019-10-08-notes.md ├── 2019-10-16-notes.md └── 2019-10-29-notes.md ├── nwp-directory.md ├── nwpstatus.md ├── onboarding.md └── swp-onboarding-sample.json /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Bug report \U0001F41B" 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Additional context** 24 | Add any other context about the problem here. 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/comment-or-question---.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Comment or question ⁉️ 3 | about: Give a comment or ask a question 4 | title: '' 5 | labels: comment, question 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Text passage in a document** 11 | Specify which text passage in which document you want to comment on or ask a question about. 12 | 13 | **API operation or definition** 14 | Specify which part of the API you want to comment on or ask a question about. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: "Feature request \U0001F680" 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /LICENSE/Nutzungslizenz-SWP-API.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/LICENSE/Nutzungslizenz-SWP-API.docx -------------------------------------------------------------------------------- /LICENSE/Nutzungslizenz-SWP-API.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/LICENSE/Nutzungslizenz-SWP-API.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ebill-swp-api 2 | 3 | The **eBill Software Partner API** (eBill SWP API) defines an interface used to deliver _electronic invoices_ 4 | from an ERP to an _eBill Network Partner_ (as defined by SIX). 5 | 6 | ## Status 7 | 8 | Version 1.0 is final as of Sept 28th 2020. Please feel free to ask questions or leave comments using _GitHub issues_. 9 | 10 | ## API definition 11 | 12 | The API is available both in English and in German: 13 | 14 | 15 | 16 | - [SIX eBill SWP API: Recommendation for the Interface between Software Manufacturers and Network Partners of SIX eBill](https://github.com/swico/ebill-swp-api/blob/master/documents/InterfaceRecommendationSIXeBill-1.0.pdf) – PDF document, Version 1.0 17 | - [SIX eBill SWP API: Empfehlung für die Schnittstelle zwischen Softwareherstellern und Netzwerkpartnern der SIX eBill](https://github.com/swico/ebill-swp-api/blob/master/documents/SchnittstellenempfehlungSIXeBill-1.0.pdf) – PDF document, Version 1.0 18 | - [eBill-Softwarepartner zu Netzwerkpartner API Lizenz- und Nutzungsbedingungen](https://github.com/swico/ebill-swp-api/blob/master/LICENSE/Nutzungslizenz-SWP-API.pdf) – PDF document, Draft 0.5 19 | 20 | The API definition can be found as a Swagger YAML-file in folder `api` and viewed, 21 | for instance, with an online tool such as [swagger.io](https://editor.swagger.io). 22 | 23 | See also the document about the [onboarding process](https://github.com/swico/ebill-swp-api/tree/master/documents/onboarding.md). 24 | 25 | ## NWP Directory 26 | 27 | The [NWP Directory](https://github.com/swico/ebill-swp-api/tree/master/documents/nwp-directory.md) lists in human-readable 28 | form the currently assigned PID prefixes. 29 | 30 | ## Who's involved 31 | 32 | The informal workgroup members as of July 2022: 33 | 34 | - Abacus: Remo Knaus 35 | - Avaloq Outline: Gino Campolo 36 | - Billte: Andrea Girasole and Srdjan Micic 37 | - Epsitec: **Pierre Arnaud** 38 | - GS1: Simon Zbinden 39 | - InvoCloud / Nintu Informatik: Beat Meier 40 | - Medidata: Stefan Staehli 41 | - Messerli Informatik, Roland Messerli 42 | - SIX: Fabio Serratore 43 | - xeFex AG: **Nicolas Guillet** 44 | - **Eva Sediki** 45 | 46 | Translation of the _interface recommendation_ was managed by Adrian Kaufmann (SIX). 47 | The workgroup is also supported by Oliver Jenny (SIX) and Thomas Reske (SIX). 48 | 49 | Thanks to SIX and also to Giancarlo Palmisani from SWICO and Simon Zbinden from GS1 50 | -------------------------------------------------------------------------------- /api/swp-nwp-api-v1-swagger.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | description: | 4 | The application programming interface for software partners (Software Partner API) allows communication with an eBill Network Partner. 5 | The eBill service comprises of electronic bills, reminders, credit notes and advices which are summarized under the term "business case". Business cases are delivered from software partners via network partners to the SIX eBill infrastructure and can be received online by bill recipients. 6 | 7 | Documentation and Open API licence of the Software Partner API can be found on https://ebill-swp.org 8 | 9 | ### General Note 10 | 11 | The Working Group eBill-SWP-API reserves the right to amend this documentation as required. 12 | 13 | This documentation has been compiled with the greatest care, but may nevertheless contain errors or inaccuracies. Working Group eBill-SWP-API cannot assume any legal responsibility or any liability for erroneous information or its consequences. 14 | 15 | If you notice any errors in this documentation or have any suggestions for improvements, we would be grateful to receive your feedback; please open an issue on our website. 16 | 17 | version: 1.0.2 18 | title: Software Partner API v1 19 | contact: 20 | name: 'Software Partner API' 21 | url: 'https://ebill-swp.org' 22 | host: api.mynwp.ch 23 | basePath: /swp/v1 24 | tags: 25 | - name: billers 26 | description: | 27 | **Biller Management** 28 | All operations that are associated with a biller are located within the biller resource, including the creation of business cases. 29 | - name: events 30 | description: | 31 | **Notification Events** 32 | The event resource allows the software partner to retrieve changes for the event type 'Subscription status changes'. 33 | - name: sectors 34 | description: | 35 | **Industry Sector** 36 | Industry sectors are valid system wide. Each biller will reference one or several industry sectors. 37 | - name: healthcheck 38 | description: | 39 | **System Healthcheck** 40 | This allows to check the basic state of the system (can it be reached, does authentication and auhorization work, does it respond). As some infrastructures block certain HTTP methods by default, the healthcheck allows to test if all required methods (GET, POST) work across all layers. 41 | schemes: 42 | - https 43 | paths: 44 | '/billers/{billerPid}/bill-recipients/search': 45 | parameters: 46 | - $ref: '#/parameters/path_billerPid' 47 | - $ref: '#/parameters/header_authorization' 48 | - $ref: '#/parameters/header_xCorrelationId' 49 | post: 50 | tags: 51 | - billers 52 | summary: Search for bill recipients for this biller 53 | description: | 54 | Returns a list of one or more bill recipients. 55 | 56 | The response will only list a bill recipient if he allows bills to be 57 | posted by the biller or allows bills to be posted in general. It will always return the billRecipientId and optionally any other provided parameter. 58 | 59 | The call will return an empty list if no matching bill recipient is 60 | found or the biller is not allowed to send bills to the bill recipient. 61 | operationId: searchBillRecipientsForBiller 62 | parameters: 63 | - in: body 64 | name: body 65 | description: | 66 | Parameters for the search, at least one of the parameters is 67 | required 68 | required: true 69 | schema: 70 | $ref: '#/definitions/BillRecipientsForBillerSearchRequest' 71 | consumes: 72 | - application/json 73 | produces: 74 | - application/json 75 | responses: 76 | '200': 77 | description: Bill recipients found 78 | schema: 79 | type: array 80 | items: 81 | $ref: '#/definitions/BillRecipientsForBillerSearchResponse' 82 | default: 83 | description: | 84 | See section Error Handling of the Software Partner API documentation 85 | for further details about errors and error handling. 86 | schema: 87 | $ref: '#/definitions/Problem' 88 | '/billers/{billerPid}/business-cases': 89 | parameters: 90 | - $ref: '#/parameters/path_billerPid' 91 | - $ref: '#/parameters/header_authorization' 92 | - $ref: '#/parameters/header_xCorrelationId' 93 | - $ref: '#/parameters/header_xFilename' 94 | - $ref: '#/parameters/header_xBusinessCaseFormat' 95 | - $ref: '#/parameters/header_xBusinessCaseFunction' 96 | post: 97 | tags: 98 | - billers 99 | summary: Create business case in PDF/A-3b-format 100 | operationId: createBusinessCase 101 | description: | 102 | The creation of a business case in PDF/A-3b format works with a simple 103 | POST request where the PDF is the binary payload of the request. Note 104 | that only one PDF can be submitted at a time. 105 | 106 | Validation of the submitted data will take place immediately and the 107 | response either confirms the successful creation of the business case on 108 | the NWP or contains the error details of the validation. 109 | 110 | Technical Hint: 111 | 112 | Note that this POST operation is not officially supported by the 113 | 114 | specification language 'OAS 2.0' ('Swagger 2.0') as described in detail 115 | 116 | here -> 'https://swagger.io/docs/specification/2-0/file-upload/' 117 | consumes: 118 | - application/pdf 119 | parameters: 120 | - in: body 121 | name: body 122 | description: PDF as binary data with attached file for structured data 123 | required: true 124 | schema: 125 | type: string 126 | format: binary 127 | produces: 128 | - application/json 129 | responses: 130 | '201': 131 | description: Business case created 132 | schema: 133 | $ref: '#/definitions/BusinessCaseId' 134 | default: 135 | description: | 136 | See section Error Handling of the Software Partner API documentation 137 | for further details about errors and error handling. 138 | schema: 139 | $ref: '#/definitions/Problem' 140 | '/billers/{billerPid}/business-cases/{businessCaseId}': 141 | parameters: 142 | - $ref: '#/parameters/path_billerPid' 143 | - $ref: '#/parameters/path_businessCaseId' 144 | - $ref: '#/parameters/header_authorization' 145 | - $ref: '#/parameters/header_xCorrelationId' 146 | get: 147 | tags: 148 | - billers 149 | summary: Get business case 150 | description: | 151 | Depending on the accept header, this operation either returns a JSON business case object or the original PDF. 152 | The returned JSON object contains one of the business case subtypes: 153 | Bill, InstalmentBill, Reminder, CreditNote or Advice. 154 | operationId: getBusinessCase 155 | produces: 156 | - application/json 157 | - application/pdf 158 | responses: 159 | '200': 160 | description: Business case found 161 | schema: 162 | $ref: '#/definitions/BusinessCase' 163 | default: 164 | description: | 165 | See section Error Handling of the Software Partner API documentation 166 | for further details about errors and error handling. 167 | schema: 168 | $ref: '#/definitions/Problem' 169 | /events/business-case-status-changed: 170 | parameters: 171 | - $ref: '#/parameters/query_lastEventId' 172 | - $ref: '#/parameters/query_limitEvents' 173 | - $ref: '#/parameters/header_authorization' 174 | - $ref: '#/parameters/header_xCorrelationId' 175 | get: 176 | tags: 177 | - events 178 | summary: Find events for business cases which changed status 179 | description: | 180 | Events for status changes of bills, advices, credit notes and reminders 181 | which belong to any billerPid registered with the requesting SWP. 182 | operationId: findBusinessCaseStatusChangedEvents 183 | produces: 184 | - application/json 185 | responses: 186 | '200': 187 | description: Business case status changed events found 188 | schema: 189 | type: array 190 | items: 191 | $ref: '#/definitions/BusinessCaseStatusChangedEvent' 192 | default: 193 | description: | 194 | See section Error Handling of the Network Partner API documentation 195 | for further details about errors and error handling. 196 | schema: 197 | $ref: '#/definitions/Problem' 198 | /events/instalment-status-changed: 199 | parameters: 200 | - $ref: '#/parameters/query_lastEventId' 201 | - $ref: '#/parameters/query_limitEvents' 202 | - $ref: '#/parameters/header_authorization' 203 | - $ref: '#/parameters/header_xCorrelationId' 204 | get: 205 | tags: 206 | - events 207 | summary: Find events for instalments which changed status 208 | description: | 209 | Events for status changes of instalment bills only which belong to any 210 | billerPid registered with the requesting SWP. 211 | operationId: findInstalmentStatusChangedEvents 212 | produces: 213 | - application/json 214 | responses: 215 | '200': 216 | description: Instalment status changed events found 217 | schema: 218 | type: array 219 | items: 220 | $ref: '#/definitions/InstalmentStatusChangedEvent' 221 | default: 222 | description: | 223 | See section Error Handling of the Network Partner API documentation 224 | for further details about errors and error handling. 225 | schema: 226 | $ref: '#/definitions/Problem' 227 | /events/bill-recipient-email-address-changed: 228 | parameters: 229 | - $ref: '#/parameters/query_lastEventId' 230 | - $ref: '#/parameters/query_limitEvents' 231 | - $ref: '#/parameters/header_authorization' 232 | - $ref: '#/parameters/header_xCorrelationId' 233 | get: 234 | tags: 235 | - events 236 | summary: Find events for bill recipients email address changes 237 | description: | 238 | This event is triggered after any billerPid registered with the requesting SWP has submitted a business case with an outdated, so called historically available email address. It notifies about the changed email address of a bill recipient, which has been adjusted in eBill. 239 | An email address is considered to be historically available if it was present up to 15 months prior to the submission time. 240 | The billers are able to submit business cases with historically available email addresses of a bill recipient. However, latest 15 months after the email address changed, the billers are required to submit the business cases with the currently valid email address of the bill 241 | recipient. 242 | operationId: findBillRecipientEmailAddressChangedEvent 243 | produces: 244 | - application/json 245 | responses: 246 | '200': 247 | description: Bill recipient email address changed events found 248 | schema: 249 | type: array 250 | items: 251 | $ref: '#/definitions/BillRecipientEmailAddressChangedEvent' 252 | default: 253 | description: | 254 | See section Error Handling of the Network Partner API documentation for further details about errors and error handling. 255 | schema: 256 | $ref: '#/definitions/Problem' 257 | /events/bill-recipient-subscription-status-changed: 258 | parameters: 259 | - $ref: '#/parameters/query_lastEventId' 260 | - $ref: '#/parameters/query_limitEvents' 261 | - $ref: '#/parameters/header_authorization' 262 | - $ref: '#/parameters/header_xCorrelationId' 263 | get: 264 | tags: 265 | - events 266 | summary: Find events for bill recipient subscriptions which changed status 267 | description: | 268 | Events for status changes on bill recipient subscriptions to any billerPid registered with the requesting SWP, regardless if subscriptions have been done without registration form (event from infrastructure) or with registration form (no event from infrastructure). 269 | operationId: findBillRecipientSubscriptionStatusChangedEvents 270 | produces: 271 | - application/json 272 | responses: 273 | '200': 274 | description: Bill recipient subscription changed events found 275 | schema: 276 | type: array 277 | items: 278 | $ref: '#/definitions/BillRecipientSubscriptionStatusChangedEvent' 279 | default: 280 | description: | 281 | See section Error Handling of the Software Partner API documentation for further details about errors and error handling. 282 | schema: 283 | $ref: '#/definitions/Problem' 284 | /sectors: 285 | parameters: 286 | - $ref: '#/parameters/header_authorization' 287 | - $ref: '#/parameters/header_xCorrelationId' 288 | get: 289 | tags: 290 | - sectors 291 | summary: 'Find Sectors' 292 | description: 'Get the industry sector list of the eBill infrastructure. The sectors are more or less static and can therefore be cached.' 293 | operationId: findSectors 294 | produces: 295 | - application/json 296 | responses: 297 | '200': 298 | description: 'Sectors found' 299 | schema: 300 | type: array 301 | items: 302 | $ref: '#/definitions/Sector' 303 | 'default': 304 | description: 'See section Error Handling of the Network Partner API documentation for further details about errors and error handling.' 305 | schema: 306 | $ref: '#/definitions/Problem' 307 | /healthcheck: 308 | parameters: 309 | - $ref: '#/parameters/header_authorization' 310 | - $ref: '#/parameters/header_xCorrelationId' 311 | get: 312 | tags: 313 | - healthcheck 314 | summary: Health check using GET method 315 | description: Returns a status message of the system. 316 | operationId: healthCheckForGet 317 | produces: 318 | - application/json 319 | responses: 320 | '200': 321 | description: Healthcheck successful 322 | schema: 323 | $ref: '#/definitions/HealthCheckResponse' 324 | default: 325 | description: | 326 | See section Error Handling of the Software Partner API documentation for further details about errors and error handling. 327 | schema: 328 | $ref: '#/definitions/Problem' 329 | post: 330 | tags: 331 | - healthcheck 332 | summary: Health check using POST method 333 | description: Returns the request body. This operation will not modify the system. 334 | operationId: healthCheckForPost 335 | parameters: 336 | - in: body 337 | name: body 338 | description: Any message which is expected in the response 339 | required: true 340 | schema: 341 | $ref: '#/definitions/HealthCheckRequest' 342 | consumes: 343 | - application/json 344 | produces: 345 | - application/json 346 | responses: 347 | '200': 348 | description: Healthcheck successful 349 | schema: 350 | $ref: '#/definitions/HealthCheckResponse' 351 | default: 352 | description: | 353 | See section Error Handling of the Software Partner API documentation for further details about errors and error handling. 354 | schema: 355 | $ref: '#/definitions/Problem' 356 | securityDefinitions: 357 | oauth2_cg: 358 | type: oauth2 359 | description: OAuth2 based authentication with authorization code grant. 360 | flow: accessCode 361 | scopes: 362 | default-biller: default scope for biller 363 | tokenUrl: 'https://api.mynwp.com/oauth/v1/token' 364 | authorizationUrl: 'https://api.mynwp.com/oauth/v1/authorize' 365 | parameters: 366 | path_billerPid: 367 | name: billerPid 368 | in: path 369 | type: string 370 | description: | 371 | biller PID 372 | **Maximal length**: `17` 373 | **Example**: `"41100012345678901"` 374 | **Pattern**: `41[0-9]{15}` 375 | required: true 376 | maxLength: 17 377 | pattern: '41[0-9]{15}' 378 | path_businessCaseId: 379 | name: businessCaseId 380 | in: path 381 | type: string 382 | description: | 383 | business case id 384 | **Maximal length**: `39` 385 | **Example**: `"NWPBCID0FB909852BBC4D06AD8336AAE87D7FC9"` 386 | **Pattern**: `NWPBCID[0-9A-Z]{32}` 387 | required: true 388 | pattern: 'NWPBCID[0-9A-Z]{32}' 389 | maxLength: 39 390 | query_lastEventId: 391 | name: lastEventId 392 | in: query 393 | type: string 394 | maxLength: 39 395 | pattern: 'NWPEVID[0-9A-Z]{32}' 396 | description: | 397 | Id of the last received event. If omitted, the result starts with the oldest available event. 398 | **Example**: `"NWPEVID82A65938766547EBBBA39BA6F7B07F24"` 399 | **Maximal length**: `39` 400 | **Pattern**: `"NWPEVID[0-9A-Z]{32}"` 401 | query_limitEvents: 402 | name: limit 403 | in: query 404 | type: integer 405 | description: | 406 | Maximum number of events one wants to receive (technical maximum is 10000, no more will be returned at once and you have to fetch again to check if there are more) 407 | maximum: 10000 408 | default: 1000 409 | header_xCorrelationId: 410 | name: X-CORRELATION-ID 411 | in: header 412 | type: string 413 | minLength: 1 414 | maxLength: 36 415 | required: true 416 | description: | 417 | ID which will unambiguously identify this request to the API. 418 | **Minimal length**: `1` 419 | **Maximal length**: `36` 420 | header_authorization: 421 | name: Authorization 422 | in: header 423 | type: string 424 | required: true 425 | description: | 426 | OAuth 2.0 client credentials Access-Token with the prefix "Bearer". 427 | header_xFilename: 428 | name: X-FILENAME 429 | in: header 430 | type: string 431 | minLength: 1 432 | maxLength: 99 433 | required: false 434 | description: | 435 | Filename for the business case PDF. This is only used for analytical purposes and support. The filename is not visible for the bill recipient. 436 | **Minimal length**: `1` 437 | **Maximal length**: `99` 438 | header_xBusinessCaseFormat: 439 | name: X-BCFORMAT 440 | in: header 441 | type: string 442 | required: false 443 | description: Format of the business case. 444 | enum: 445 | - zugferd.EN16931 446 | - zugferd.EXTENDED 447 | - zugferd.BasicWL 448 | - fscmxml 449 | - yellowbill 450 | - qrbill 451 | header_xBusinessCaseFunction: 452 | name: X-BCFUNCTION 453 | in: header 454 | type: string 455 | required: false 456 | description: Function of the business case. 457 | enum: 458 | - bill 459 | - creditnote 460 | - advice 461 | - reminder 462 | responses: 463 | BadRequest: 464 | description: bad request 465 | schema: 466 | $ref: '#/definitions/Problem' 467 | Unauthorized: 468 | description: unauthorized 469 | schema: 470 | $ref: '#/definitions/Problem' 471 | Forbidden: 472 | description: forbidden 473 | schema: 474 | $ref: '#/definitions/Problem' 475 | NotFound: 476 | description: the specified resource was not found 477 | schema: 478 | $ref: '#/definitions/Problem' 479 | definitions: 480 | Address: 481 | type: object 482 | required: 483 | - streetName 484 | - postalCode 485 | - city 486 | - countryCode 487 | properties: 488 | streetName: 489 | type: string 490 | description: street name 491 | example: Neustadtstrasse 492 | minLength: 1 493 | maxLength: 70 494 | buildingNumber: 495 | type: string 496 | description: building number 497 | example: 20a 498 | minLength: 1 499 | maxLength: 16 500 | postalCode: 501 | type: string 502 | description: postal code 503 | example: '6025' 504 | minLength: 1 505 | maxLength: 9 506 | city: 507 | type: string 508 | description: city name 509 | example: Neudorf 510 | minLength: 1 511 | maxLength: 35 512 | countryCode: 513 | type: string 514 | description: in format ISO 3166-1 alpha 2 515 | example: CH 516 | maxLength: 2 517 | pattern: '[A-Z]{2}' 518 | BillRecipientsForBillerSearchRequest: 519 | type: object 520 | properties: 521 | emailAddress: 522 | type: string 523 | description: 'email address of the bill recipient' 524 | example: 'peter@muster.ch' 525 | minLength: 1 526 | maxLength: 256 527 | format: email 528 | billRecipientId: 529 | type: string 530 | description: 'id of the bill recipient' 531 | example: '41010560425610173' 532 | minLength: 1 533 | maxLength: 17 534 | pattern: '([0-9])*' 535 | enterpriseIdentificationNumber: 536 | type: string 537 | description: | 538 | Swiss enterprise identification number (UID) without dashes, dots or extension. 539 | Note that this has to contain the swiss enterprise identification number (UID) from the commercial register (Handelsregister) which may be different from the VAT UID (Mehrwertsteuer UID). 540 | maxLength: 12 541 | pattern: 'CHE[0-9]{9}' 542 | example: 'CHE123456789' 543 | BillRecipientsForBillerSearchResponse: 544 | type: object 545 | required: 546 | - billRecipientId 547 | properties: 548 | emailAddress: 549 | type: string 550 | description: 'email address of the bill recipient' 551 | example: 'peter@muster.ch' 552 | minLength: 1 553 | maxLength: 256 554 | format: email 555 | billRecipientId: 556 | type: string 557 | description: 'id of the bill recipient' 558 | example: '41010560425610173' 559 | minLength: 1 560 | maxLength: 17 561 | pattern: '([0-9])*' 562 | enterpriseIdentificationNumber: 563 | type: string 564 | description: | 565 | Swiss enterprise identification number (UID) without dashes, dots or extension. 566 | Note that this has to contain the swiss enterprise identification number (UID) from the commercial register (Handelsregister) which may be different from the VAT UID (Mehrwertsteuer UID). 567 | maxLength: 12 568 | pattern: 'CHE[0-9]{9}' 569 | example: 'CHE123456789' 570 | BillRecipientSubscription: 571 | type: object 572 | required: 573 | - billerPid 574 | - billRecipient 575 | properties: 576 | billerPid: 577 | type: string 578 | description: biller PID 579 | maxLength: 17 580 | pattern: '41[0-9]{15}' 581 | example: '41100012345678901' 582 | billRecipient: 583 | $ref: '#/definitions/BillRecipient' 584 | accountNumber: 585 | type: string 586 | maxLength: 21 587 | description: | 588 | Account number of the biller (e.g. iban), if provided from the financial institution 589 | referenceStructured: 590 | type: string 591 | description: | 592 | ESR or QR or creditor reference number, if provided from the financial institution. 593 | maxLength: 27 594 | example: '123456123456789012345678901' 595 | pattern: '([a-zA-Z0-9])*' 596 | BillRecipient: 597 | type: object 598 | required: 599 | - billRecipientId 600 | - type 601 | - name 602 | - correspondenceLanguage 603 | - address 604 | properties: 605 | emailAddress: 606 | type: string 607 | description: email address of the bill recipient 608 | example: peter@muster.ch 609 | minLength: 1 610 | maxLength: 256 611 | format: email 612 | billRecipientId: 613 | type: string 614 | description: id of the bill recipient 615 | example: '41010560425610173' 616 | minLength: 1 617 | maxLength: 17 618 | pattern: '([0-9])*' 619 | enterpriseIdentificationNumber: 620 | type: string 621 | description: | 622 | Swiss enterprise identification number (UID) without dashes, dots or extension. 623 | Note that this has to contain the swiss enterprise identification number (UID) from the commercial register (Handelsregister) which may be different from the VAT UID (Mehrwertsteuer UID). 624 | maxLength: 12 625 | pattern: 'CHE[0-9]{9}' 626 | example: CHE123456789 627 | type: 628 | type: string 629 | description: the type of the bill recipient 630 | enum: 631 | - PRIVATE 632 | - COMPANY 633 | name: 634 | type: string 635 | description: | 636 | last name, if private bill recipient 637 | company name, if company bill recipient 638 | example: 'for private bill recipient: Muster, for company name: Muster AG' 639 | minLength: 1 640 | maxLength: 70 641 | firstName: 642 | type: string 643 | description: | 644 | first name, if private bill recipient 645 | empty, if company bill recipient 646 | example: Peter 647 | maxLength: 35 648 | correspondenceLanguage: 649 | type: string 650 | description: language for correspondence with this bill recipient ISO-639-2/B 651 | minLength: 1 652 | maxLength: 3 653 | example: ger 654 | address: 655 | $ref: '#/definitions/Address' 656 | BusinessCase: 657 | discriminator: type 658 | required: 659 | - id 660 | - status 661 | type: object 662 | description: the business case object on the NWP 663 | properties: 664 | id: 665 | description: | 666 | A unique id for this business case on the NWP. Property must not be given when creating a new business case. 667 | type: string 668 | maxLength: 39 669 | pattern: 'NWPBCID[0-9A-Z]{32}' 670 | example: NWPBCID0FB909852BBC4D06AD8336AAE87D7FC9 671 | status: 672 | type: string 673 | description: the status of the business case 674 | enum: 675 | - NWP_PENDING 676 | - OPEN 677 | - APPROVED 678 | - REJECTED 679 | - COMPLETED 680 | BusinessCaseId: 681 | type: object 682 | required: 683 | - id 684 | properties: 685 | id: 686 | description: | 687 | A unique id for business cases on the NWP. Property must not be given when creating a new business case. 688 | type: string 689 | maxLength: 39 690 | pattern: 'NWPBCID[0-9A-Z]{32}' 691 | example: NWPBCID0FB909852BBC4D06AD8336AAE87D7FC9 692 | Event: 693 | type: object 694 | required: 695 | - eventId 696 | - timestamp 697 | description: contains common fields for all events 698 | properties: 699 | eventId: 700 | type: string 701 | description: event id 702 | example: NWPEVID82A65938766547EBBBA39BA6F7B07F24 703 | maxLength: 39 704 | pattern: 'NWPEVID[0-9A-Z]{32}' 705 | timestamp: 706 | type: string 707 | description: timestamp of the event 708 | minLength: 1 709 | format: date-time 710 | example: '2019-01-01T10:00:00.000Z' 711 | ApprovalAmountWithCurrency: 712 | description: | 713 | Amount provided by status changed events if the new status is APPROVED. The value is always greater than zero. 714 | type: object 715 | required: 716 | - value 717 | - currencyCode 718 | properties: 719 | value: 720 | $ref: '#/definitions/AmountValue' 721 | currencyCode: 722 | $ref: '#/definitions/CurrencyCode' 723 | AmountValue: 724 | description: | 725 | The amount value. Take care when using JavaScript libraries to parse this value - it should be treated as a financial amount and therefore not as a floating point number but rather using a precise decimal representation (like BigDecimal in Java). 726 | **Maximum value**: `99'999'999.99` 727 | **Maximal length**: `10` 728 | type: number 729 | example: 99.99 730 | CurrencyCode: 731 | description: | 732 | The amount currency code according to ISO-4217. 733 | type: string 734 | example: 'CHF' 735 | maxLength: 3 736 | pattern: '[A-Z]{3}' 737 | BusinessCaseStatusChangedEvent: 738 | type: object 739 | required: 740 | - billerPid 741 | - businessCaseId 742 | - newStatus 743 | description: | 744 | An Event describing the status change of a business case. These events are sent for bills, reminders, advices and credit notes. The approved amount is only provided for the status APPROVED. 745 | allOf: 746 | - $ref: '#/definitions/Event' 747 | - properties: 748 | billerPid: 749 | type: string 750 | description: biller PID 751 | maxLength: 17 752 | pattern: '41[0-9]{15}' 753 | example: '41100012345678901' 754 | businessCaseId: 755 | type: string 756 | description: business case id 757 | maxLength: 39 758 | pattern: 'NWPBCID[0-9A-Z]{32}' 759 | example: NWPBCID0FB909852BBC4D06AD8336AAE87D7FC9 760 | newStatus: 761 | type: string 762 | description: the new status of the business case 763 | enum: 764 | - NWP_PENDING 765 | - OPEN 766 | - APPROVED 767 | - REJECTED 768 | - COMPLETED 769 | approvedAmount: 770 | $ref: '#/definitions/ApprovalAmountWithCurrency' 771 | InstalmentStatusChangedEvent: 772 | type: object 773 | required: 774 | - billerPid 775 | - businessCaseId 776 | - externalInstalmentId 777 | - externalPaymentByInstalmentsId 778 | - newStatus 779 | description: | 780 | An Event describing the status change of an instalment. These events are only sent for instalment bills. The approved amount is only provided for the status APPROVED. 781 | allOf: 782 | - $ref: '#/definitions/Event' 783 | - properties: 784 | billerPid: 785 | type: string 786 | description: biller PID 787 | maxLength: 17 788 | pattern: '41[0-9]{15}' 789 | example: '41100012345678901' 790 | businessCaseId: 791 | type: string 792 | description: 'business case id' 793 | maxLength: 39 794 | pattern: 'NWPBCID[0-9A-Z]{32}' 795 | example: 'NWPBCID0FB909852BBC4D06AD8336AAE87D7FC9' 796 | externalPaymentByInstalmentsId: 797 | type: string 798 | description: 'external id of the respective paymentByInstalment' 799 | minLength: 1 800 | maxLength: 36 801 | example: '298031-2999' 802 | externalInstalmentId: 803 | type: string 804 | description: 'external id of the instalment' 805 | minLength: 1 806 | maxLength: 36 807 | example: '298031-2999-ACX01' 808 | newStatus: 809 | type: string 810 | description: 'the new status of the instalment' 811 | enum: 812 | - NWP_PENDING 813 | - OPEN 814 | - APPROVED 815 | - REJECTED 816 | - COMPLETED 817 | approvedAmount: 818 | $ref: '#/definitions/ApprovalAmountWithCurrency' 819 | BillRecipientSubscriptionStatusChangedEvent: 820 | type: object 821 | required: 822 | - newStatus 823 | description: | 824 | An Event describing the status change of a bill recipient subscription. 825 | Additional properties may be filled according the user input on the biller\'s registration form. 826 | allOf: 827 | - $ref: '#/definitions/Event' 828 | - $ref: '#/definitions/BillRecipientSubscription' 829 | - properties: 830 | newStatus: 831 | type: string 832 | description: | 833 | The new status of the bill recipient subscription, currently only 834 | REQUESTED and INACTIVE are used, see <> for further information. 836 | enum: 837 | - INACTIVE 838 | - REQUESTED 839 | - ACTIVE 840 | - additionalProperties: true 841 | BillRecipientEmailAddressChangedEvent: 842 | type: object 843 | required: 844 | - oldEmailAddress 845 | - newEmailAddress 846 | - triggeredBy 847 | description: 'An Event describing the change of the email address of a bill recipient.' 848 | allOf: 849 | - $ref: '#/definitions/Event' 850 | - properties: 851 | oldEmailAddress: 852 | type: string 853 | description: 'the old email address of the bill recipient which has been used in the submission of a business case' 854 | example: 'peter@muster.ch' 855 | minLength: 1 856 | maxLength: 256 857 | format: email 858 | newEmailAddress: 859 | type: string 860 | description: 'the new email address of the bill recipient' 861 | example: 'peter_new@muster.ch' 862 | minLength: 1 863 | maxLength: 256 864 | format: email 865 | triggeredBy: 866 | type: object 867 | required: 868 | - businessCaseId 869 | - billerPid 870 | properties: 871 | businessCaseId: 872 | type: string 873 | description: 'business case id' 874 | maxLength: 39 875 | pattern: 'NWPBCID[0-9A-Z]{32}' 876 | example: 'NWPBCID0FB909852BBC4D06AD8336AAE87D7FC9' 877 | billerPid: 878 | type: string 879 | description: biller PID 880 | maxLength: 17 881 | pattern: '41[0-9]{15}' 882 | example: '41100012345678901' 883 | Sector: 884 | type: object 885 | properties: 886 | id: 887 | description: A unique id for this sector. 888 | type: string 889 | example: 'SCID0000000000' 890 | maxLength: 14 891 | pattern: 'SCID[0-9]{10}' 892 | localizedData: 893 | type: object 894 | properties: 895 | ger: 896 | $ref: '#/definitions/LocalizedSectorData' 897 | fre: 898 | $ref: '#/definitions/LocalizedSectorData' 899 | ita: 900 | $ref: '#/definitions/LocalizedSectorData' 901 | eng: 902 | $ref: '#/definitions/LocalizedSectorData' 903 | LocalizedSectorData: 904 | type: object 905 | required: 906 | - name 907 | properties: 908 | name: 909 | type: string 910 | description: 'name of the sector' 911 | minLength: 1 912 | maxLength: 36 913 | example: 'Transport' 914 | Problem: 915 | type: object 916 | properties: 917 | type: 918 | type: string 919 | format: uri 920 | description: | 921 | An absolute URI that identifies the problem type. 922 | We may provide human-readable documentation for the problem type in the future, when the URI is dereferenced. 923 | For now consult the Software Partner API documentation for further information. 924 | The URI consists of the /problems endpoint and the documented problem type, see example. 925 | default: 'about:blank' 926 | example: /problems/REQUEST_BODY_VALIDATION_FAILED 927 | title: 928 | type: string 929 | description: A short, human readable summary of the problem type. 930 | example: Payload has missing or invalid values 931 | status: 932 | type: integer 933 | format: int32 934 | description: | 935 | The HTTP status code generated by the origin server for this occurrence of the problem. 936 | minimum: 100 937 | maximum: 600 938 | exclusiveMaximum: true 939 | example: 400 940 | detail: 941 | type: string 942 | description: | 943 | A human readable explanation specific to this occurrence of the problem. 944 | example: | 945 | The submitted request contains invalid or missing data which can not be processed. 946 | instance: 947 | type: string 948 | format: uri 949 | description: | 950 | An absolute URI that identifies the specific occurrence of the problem. 951 | It may or may not yield further information if dereferenced. 952 | example: | 953 | /swp/v1/biller/errors/NWPBCID0090000001/provided-X-CORRELATION-ID 954 | technicalReason: 955 | type: string 956 | description: | 957 | The Technical Description/Reason for engineers might contain addition system information on the problem. 958 | example: Some field validations failed 959 | fieldErrors: 960 | type: array 961 | items: 962 | type: object 963 | properties: 964 | fieldName: 965 | type: string 966 | description: the name of the field with the error 967 | example: localizedData.ger.address.city 968 | message: 969 | type: string 970 | description: the message describing the error 971 | example: size must be between 1 and 35 972 | rejectedValue: 973 | type: string 974 | description: the provided value which was rejected if available 975 | example: Very Long Invalid City Name Which Is Rejected 976 | HealthCheckRequest: 977 | type: object 978 | required: 979 | - message 980 | properties: 981 | message: 982 | type: string 983 | description: expected response message from health check 984 | example: any string 985 | minLength: 1 986 | maxLength: 100 987 | HealthCheckResponse: 988 | type: object 989 | required: 990 | - message 991 | - requestDateTime 992 | - receivedHeaders 993 | - environmentStage 994 | - applicationVersion 995 | - apiVersion 996 | properties: 997 | message: 998 | type: string 999 | description: response message from health check 1000 | example: The healthcheck GET resp. POST request was successfully received and processed 1001 | maxLength: 100 1002 | requestDateTime: 1003 | type: string 1004 | description: | 1005 | according to RFC3339, section 5.6 in ISO 8601 with timezone and milliseconds 1006 | format: date-time 1007 | example: '2018-10-03T16:03:09.101+02:00' 1008 | receivedHeaders: 1009 | type: array 1010 | items: 1011 | type: object 1012 | properties: 1013 | headerName: 1014 | type: string 1015 | description: the name of the provided header 1016 | example: X-CORRELATION-ID 1017 | headerValue: 1018 | type: string 1019 | description: As received 1020 | example: 9bcd4351-4b7b-4017-9b63-9613414c6ff1 1021 | environmentStage: 1022 | type: string 1023 | description: the instance which the request was sent to 1024 | example: XE 1025 | applicationVersion: 1026 | type: string 1027 | description: the version of the server application at network partner 1028 | example: 1.4.3.0-desire-20180927091004161-71-5e3ca91 1029 | apiVersion: 1030 | type: string 1031 | description: the version of the software partner api 1032 | example: 1.0.23 1033 | 1034 | -------------------------------------------------------------------------------- /documents/InterfaceRecommendationSIXeBill-1.0.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/InterfaceRecommendationSIXeBill-1.0.docx -------------------------------------------------------------------------------- /documents/InterfaceRecommendationSIXeBill-1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/InterfaceRecommendationSIXeBill-1.0.pdf -------------------------------------------------------------------------------- /documents/InterfaceRecommendationSIXeBill-1.01.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/InterfaceRecommendationSIXeBill-1.01.docx -------------------------------------------------------------------------------- /documents/InterfaceRecommendationSIXeBill-1.01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/InterfaceRecommendationSIXeBill-1.01.pdf -------------------------------------------------------------------------------- /documents/SchnittstellenempfehlungSIXeBill-1.0.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/SchnittstellenempfehlungSIXeBill-1.0.docx -------------------------------------------------------------------------------- /documents/SchnittstellenempfehlungSIXeBill-1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/SchnittstellenempfehlungSIXeBill-1.0.pdf -------------------------------------------------------------------------------- /documents/SchnittstellenempfehlungSIXeBill-1.01.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/SchnittstellenempfehlungSIXeBill-1.01.docx -------------------------------------------------------------------------------- /documents/SchnittstellenempfehlungSIXeBill-1.01.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swico/ebill-swp-api/b0f0280590dbb99207425bcff09ccd3d9c04ea56/documents/SchnittstellenempfehlungSIXeBill-1.01.pdf -------------------------------------------------------------------------------- /documents/meeting-notes/2019-10-08-notes.md: -------------------------------------------------------------------------------- 1 | # Meeting notes 2 | 3 | Zurich, Swico, October 8. 2019 4 | 5 | ## Participants 6 | 7 | - Nicolas Guillet and Remo Knaus, Abacus 8 | - Gianni Micic, Billte 9 | - Pierre Arnaud, Epsitec 10 | - Roland Messerli, Messerli Informatik 11 | - Eva Sediki, Nintu Informatik 12 | - Fabio Serratore, SIX 13 | 14 | ## Reference material 15 | 16 | - [Swiss QR Invoice](https://www.swiss-qr-invoice.org) 17 | - [Spec. for using eBill Alternative Procedure in the Swiss QR Code](https://www.ebill.ch/dam/downloads/specifications/d0482-en-01-specifications-for-using-the-ebill-alternative-procedure-in.pdf) - ebill.ch. 18 | - [NWP Technical Documentation](https://www.ebill.ch/dam/downloads/network-partners/nwp-api-specs-en.zip) - ebill.ch. 19 | - [Elektronische Hybridrechnung PDF mit XML](https://shop.gs1.ch/img/A~16970/20/Elektronische%20Hybrid.pdf?xet=1517299208724) - Basierend auf ZUGFeRD/Factur-X, GS1. 20 | 21 | ## Preliminary discussions 22 | 23 | ### About ZUGFeRD 24 | 25 | > ZUGFeRD 2 bzw. EN16931 haben leider auch ein paar Nachteile, vor allem lässt sich das normale Fälligkeitsdatum nicht abbilden, Skonto auch nicht. Und auf Positionsebene kann der Betrag nicht inkl. MWST abgebildet werden, was sehr schade ist. Sonstige CH-Eigenheiten wie ESR und QR lassen sich aber abbilden, und das ist dank GS1 auch standardisiert. 26 | > 27 | > Zu überlegen wäre, ob sich die Schweizer ERP-Hersteller einigen könnten, den /40/-Teil vom Swico-String der QR-Rechnung in ein Textfeld von ZUGFeRD abzufüllen, natürlich mit einem sinnvollen Prefix, damit alle Regeln eingehalten werden. Falls wir das machen wollen wäre GS1 natürlich prädestiniert, das zu managen. 28 | 29 | ## To be discussed 30 | 31 | ### API Deep Dive 32 | 33 | See below. 34 | 35 | ### API Definiton with respect to SIX specification 36 | 37 | We should stay as near as possible to the SIX specification in order to limit the documentation work required in the future. 38 | 39 | ### Should the API support all business cases? 40 | 41 | The _Alternative Procedure Parameters_ defined by SIX only define a mapping from a QR-bill to `B` (`Bill`) or `R` (`Reminder`). What about the `InstalmentBill`, `CreditNote` and `Advice` business cases? 42 | 43 | → Yes, but not for all PDF formats. 44 | 45 | ### What type of attachments should the API support for PDF/A-3 uploads? 46 | 47 | 1. No attachment; information is extracted from the QR-code of the QR-bill. 48 | > Multipage documents? 49 | > Multiple QR-codes? 50 | > Bad quality of QR-code image 51 | 2. XML-eBill attachment. 52 | > Not every information in QR-bill can be mapped to XML-eBill (element `/40/`). 53 | 3. XML-ZUGFeRD attachment (GS1). 54 | 4. TXT-QR attachment. 55 | 5. In the future, also proprietary Paynet or PostFinance XML attachments... 56 | 57 | → for now, we settle for **QR-code** "raw" without any additional metadata, and **XML-eBill** attachment. 58 | 59 | ## PDF 60 | 61 | - The NWP is (currently) responsible for the signing of the PDF provided by the SWP. In the future, it would be of interest that the SIX infrastructure signs the PDF (the NWP does not want to be considered as accountable for a malicious PDF delivered by the SWP). 62 | - A single PDF/A-3 with attachments is the only acceptable input media, independent of the format of the metadata. 63 | - The PDF provided by the SWP to the NWP is not the same as the PDF delivered to the customer, because of the potentially synthesized XML-eBill attachment and the NWP signature. The SWP has to archive the PDF, as sent to the eBill network, and therefore **needs to be able to retrieve the PDF from the SWP**. 64 | For this, use `/billers/{billerId}/business-cases/{businessCaseId}` with media type `application/pdf`. 65 | 66 | ## Suggested API changes 67 | 68 | We include the `billerId` as a parameter for all `billers` routes. 69 | 70 | `billers/{billerId}/bill-recipients/search` 71 | 72 | `billers/{billerId}/bill-recipients/bulk-search` 73 | 74 | `billers/{billerId}/business-cases` 75 | 76 | → additional endpoints based on the type of metadata stored in the PDF? 77 | _No, an optional parameter should be used to specify the provided metadata format_ (`ebill`, `qrbill`). 78 | 79 | → since the API must respond immediately with a business case ID, the NWP does not return the _real_ business case of the eBill infrastructure. This allows for buffering in case of system overload. 80 | 81 | → a reply with status `NWP_PENDING` is returned if the business was not yet delivered to the eBill infrastructure, otherwise the _real_ status code from SIX will be provided. 82 | 83 | ```json 84 | { 85 | "id": "NWPBCID0FB909852BBC4D06AD8336AAE87D7FC9", 86 | "status": "NWP_PENDING" 87 | } 88 | ``` 89 | 90 | `billers/{billerId}/business-cases/{businessCaseId}` 91 | 92 | → same return value as for the `POST`. 93 | 94 | `events/business-case-status-changed` 95 | 96 | → return events for all biller IDs registered with a SWP. 97 | 98 | `events/bill-recipient-email-address-changed` 99 | 100 | → is currently missing from the API definition; this would be useful to the SWP. 101 | 102 | > Note: when a user changes her email address, the infrastructure reroutes to the proper user during 15 months. 103 | 104 | `events/bill-recipient-subscription-status-changed` 105 | `events/instalment-status-changed` 106 | 107 | → return events for all biller IDs registered with a SWP. The `instalment-status-changed` is currently missing from the API definition; this is as useful (or as useless) as the `bill-recipient-subscription-status-changed` event. 108 | 109 | → this requires more thought. 110 | 111 | `healthcheck` 112 | 113 | → no brainer... 114 | 115 | ## Registering a bill recipient 116 | 117 | `events/bill-recipient-subscription-status-changed` 118 | 119 | → use this single event endpoint to retrieve all subscriptions, those from the infrastructure, and those which go through the registration form. 120 | 121 | → the `BillRecipientSubscriptionStatusChangedEvent` structure has to be extended in order to include additional key/value pairs, as provided by the user in the registration form. 122 | 123 | ## Onboarding, biller information, attachments 124 | 125 | The onboarding process is the responsibility of every NWP. 126 | This topic and other aspects are not covered by this API. 127 | 128 | ## Authentication 129 | 130 | The SWP stores following information in its software: 131 | 132 | - URL of OAuth2 server. 133 | - URL of NWP. 134 | - Biller ID. 135 | - Initial refresh token → access token, new refresh token. 136 | 137 | ## Follow-up 138 | 139 | - Authentication needs more thought. 140 | - A clear view of Level-1 (_Stufe 1_) has been defined. 141 | We need to discuss Level-2 and Level-3, mainly to include the B2B segment. 142 | - Error management needs to be clarified. 143 | Ingestion of the PDF/A-3 can generate logical errors. 144 | 145 | ## Final note 146 | 147 | - Never ever include any customer or sensitive data on GitHub. 148 | - Next meeting scheduled October 16, 13:30. 149 | -------------------------------------------------------------------------------- /documents/meeting-notes/2019-10-16-notes.md: -------------------------------------------------------------------------------- 1 | # Meeting notes 2 | 3 | Zurich, Swico, October 16. 2019 4 | 5 | ## Participants 6 | 7 | - Nicolas Guillet , Abacus 8 | - Gianni Micic, Billte 9 | - Eva Sediki, Nintu Informatik 10 | - Jean-Claude Gaechter, InvoCloud 11 | - Gino Campolo, Avaloq 12 | - Stefan Staehl, Medidata 13 | - Fabio Serratore, SIX 14 | - Andrey Moiseenko, SIX 15 | 16 | ## Reference material 17 | 18 | - [Swiss QR Invoice](https://www.swiss-qr-invoice.org) 19 | - [Spec. for using eBill Alternative Procedure in the Swiss QR Code](https://www.ebill.ch/dam/downloads/specifications/d0482-en-01-specifications-for-using-the-ebill-alternative-procedure-in.pdf) - ebill.ch. 20 | - [NWP Technical Documentation](https://www.ebill.ch/dam/downloads/network-partners/nwp-api-specs-en.zip) - ebill.ch. 21 | - [Elektronische Hybridrechnung PDF mit XML](https://shop.gs1.ch/img/A~16970/20/Elektronische%20Hybrid.pdf?xet=1517299208724) - Basierend auf ZUGFeRD/Factur-X, GS1. 22 | 23 | ## Agenda 24 | - Walk through the current SWP-API 25 | -- Onboarding 26 | -- Lookup for bill recipient: search and bulk-search 27 | - Authentication: OAuthToken versus username/password 28 | - Configuration at biller/SWP 29 | - Error management of API calls 30 | - Notification to bill recipient 31 | - Invoice formats for Level-2 (existing formats) and Level-3 (B2B formats) 32 | - API call to receive B2B invoices 33 | - Interconnect between NWPs 34 | 35 | ## Onboarding 36 | Last meeting we said: 37 | > The onboarding process is the responsibility of every NWP. This 38 | > topic and other aspects are not covered by this API. 39 | 40 | For mass onboarding, a standardized API could help NWP and biller/SWP. 41 | Should onboarding be included into the SWP-API? 42 | - Pros: standardized interface to provide biller relevant data to NWP like name, address, contact data, ESR y/n, account info. 43 | - Cons: account info is too delicate to be transfer via the API 44 | - Cons: every NWP has a different onboarding strategy; some NWPs have already implemented an onboarding procedure. 45 | 46 | 47 | → For the moment, no API calls will be added for the onboarding. 48 | → *Should this ever change, it has to be made very sure that a biller cannot change his iban with the same api. This would be a big security risk.* 49 | 50 | ## Lookup for bill recipient 51 | 52 | Two API calls exists with nearly the same interface: search and bulk-search. Wouldn't bulk-search cover both use cases? 53 | 54 | - search: if bill-recipient does not allow eBill, the call returns http error 400. So, for bulk-search another method is needed to return which bill-recipients allow eBill and which don't, e.g. returning a status for each requested bill-recipient: 55 | ```json 56 | [ 57 | { 58 | "emailAddress": "peter@muster.ch", 59 | "billRecipientId": "41010560425610173", 60 | "enterpriseIdentificationNumber": "CHE123456789", 61 | "status": "allow" 62 | } 63 | ] 64 | ``` 65 | - Proposal: SIX implements bulk-search first in NWP-API and only afterwards, SWP-API offers the same call. 66 | → The NWPs hereby officially request SIX to extend the NWP-API by the bulk-search call. 67 | 68 | → Furthermore, SIX should extend the ebill.xml so that it can hold all data provided by the QR invoice. 69 | 70 | 71 | ## Authentication 72 | Which authentication method should be used: OAuth2 or username/password? 73 | - Username/password would be easier for the biller. 74 | - OAuth 75 | -- Is used when password should not be exposed to NWP; but if NWP runs the OAuth server, the password is exposed to him. 76 | -- Content of OAuth-Token, e.g. the SIX JWT-Token consists of three parts: 77 | --- Header: 78 | `{"alg":"HS256","typ":"JWT"}` 79 | --- Payload: 80 | `{"iss":"api.six-group.com","exp":1300819380,"name":"Networkpartner 9001","sub":"NWID0090000001"}` 81 | --- Signature: 82 | `HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload),)` 83 | Each of the three parts is itself a json-content that will be Base64-encoded. 84 | -- NWP needs to look into the payload of the OAuth token to find out who is accessing the API. So, the NWP must know the structure of the token payload. 85 | → A standardized structure would be helpfull. 86 | → It would make sense, that one single OAuth-Server with a standardized payload structure exists for all NWPs. Proposal: SIX could run such a OAuth-Server. 87 | 88 | ## Configuration at biller/SWP 89 | The following configuration entries are needed in the biller's SW to use the SWP-API: 90 | 1. OAuth-URL 91 | E.g. https://api.mynwp.ch/auth/ebill/oauth/token or https://api.six-group.com/auth/swp/oauth/token 92 | 2. API-URL 93 | E.g. https://api.mynwp.ch/api/ebill 94 | Important: the version "/v1" will be added to the path by the SWP. 95 | So, the software itself specifies which version of the API to use and no configuration changes will be needed on SW upgrades. 96 | 3. BillerID 97 | Either the original SIX billerId "BIID1234567890" or a NWP specific billerId "NWPBIID1234567890". 98 | 4. Client Id 99 | E.g. an UUID. 100 | 5. Client Secret 101 | Long string, but not an UUID, because UUIDs can be guessed easily. 102 | 103 | If an external public IdP like Google is used, more config items are needed like the Google Subject ID (Google Mail address is not recommended). 104 | 105 | Are there restrictions on max lengths? 106 | 107 | ## Error management of API calls 108 | Postponed to when SWP-API is stable. Should be very similar to error management in NWP-API. 109 | 110 | ## Notification to bill recipient 111 | At the moment, exists the risk, that the bill recipient is notified about a new invoice several times by 112 | - biller 113 | - NWP 114 | - SIX infrastructure 115 | - bank 116 | 117 | → Only the biller should use the notification channel to communicate with the customer. 118 | 119 | ## Existing invoice formats 120 | Should the existing invoice formats YellowBill and EIXML (so called "Paynet format") be included in the standard? 121 | 122 | - 80-100 SWPs have already implemented the YellowBill and EIXML formats. 123 | - For processing of EIXML invoices, the NWP needs a license from SAP/Nintu. 124 | 125 | ## One Format for B2C and B2Bs: ZUGFeRD (GS1) 126 | - ZUGFeRD 2.0.1 (with swissness by GS1) corresponds to a subset of the Cross Industry Invoice (~200 fields) and is an EU standard (EN16931) 127 | - **One** format for B2C and B2B: so, no need for biller/SWP to distinguish between B2C and B2B invoices. 128 | - Not a big effort to implement on SWP; the largest effort for SWP is the implementation of the API, not in the preparation of the invoice format. 129 | - Question: Is the format ZUGFeRD 2.0.1 with the EN16031 profile enough or are further ZUGFeRD profiles needed? For example, if no line items are available? 130 | 131 | ## API call to receive B2B invoices 132 | Two endpoints are needed for a B2B customer to receive invoices: 133 | 1. Get list of available new invoices 134 | `customers/{customerId}/business-cases` 135 | Similar to how the events are fetched. 136 | 2. Get content of one new invoice 137 | `customers/{customerId}/business-cases/${businessCaseId}` 138 | 139 | ## Interconnect between NWPs 140 | - Proposal: The implementation of the SWP-API should oblige a NWP to accept B2B invoices from another NWP who implemented the SWP-API. 141 | → An obligation cannot be enforced, it can be only a recommendation. 142 | - OpenPEPPOL defines the exchange of invoices between networks, but UBL (and not ZUGFeRD) is used; CII would also be on option. 143 | 144 | ## Final note 145 | - Next meeting scheduled: 29.10.2019 13:30, SWICO, Lagerstrasse 33, Zürich 146 | 147 | Agenda: 148 | 149 | - Discussion on API / biller id in event endpoints? What else? 150 | - Onboarding process in general. How to validate sensitive data, e.g. account number? 151 | - SWP authentication at NWP, or NWPs among each other / SWP config items 152 | - B2B extension of standard API 153 | - License model for this OpenAPI 154 | - Should the EIXML be included in the standard? License from Nintu? Depends on the B2B question / Maybe all NWPs can use it if only used for SIX eBill. 155 | - eBill-API based NWP interconnect or OpenPEPPOL? Mandatory? 156 | -------------------------------------------------------------------------------- /documents/meeting-notes/2019-10-29-notes.md: -------------------------------------------------------------------------------- 1 | # Meeting notes 2 | 3 | Zurich, Schweizerhof, October 29. 2019 4 | 5 | ## Participants 6 | 7 | - Nicolas Guillet , Abacus 8 | - Remo Knaus, Abacus 9 | - Gianni Micic, Billte 10 | - Eva Sediki, Nintu Informatik 11 | - Beat Meier, Nintu Informatik 12 | - Gino Campolo, Avaloq 13 | - Stefan Staehl, Medidata 14 | - Fabio Serratore, SIX 15 | - Simon Zbinden, GS1 16 | 17 | ## Reference material 18 | 19 | - [Swiss QR Invoice](https://www.swiss-qr-invoice.org) 20 | - [Spec. for using eBill Alternative Procedure in the Swiss QR Code](https://www.ebill.ch/dam/downloads/specifications/d0482-en-01-specifications-for-using-the-ebill-alternative-procedure-in.pdf) - ebill.ch. 21 | - [NWP Technical Documentation](https://www.ebill.ch/dam/downloads/network-partners/nwp-api-specs-en.zip) - ebill.ch. 22 | - [Elektronische Hybridrechnung PDF mit XML](https://shop.gs1.ch/img/A~16970/20/Elektronische%20Hybrid.pdf?xet=1517299208724) - Basierend auf ZUGFeRD/Factur-X, GS1. 23 | 24 | ## Agenda 25 | - BillerID: PID 41xx 26 | - Authentication via AuthToken 27 | - License model for this OpenAPI 28 | - B2C formats: Should the EIXML be included in the standard? License from Nintu? 29 | - B2B extension of standard API: receive B2B invoices 30 | - Interconnect 31 | 32 | ## BillerID in SWP-API: PID 41xx, 17 digits 33 | Proposal: Instead of SIX Infrastructure's BIID, the PID should be used in the SWP-API: 41xx, 17 digits. All participants today already have such a PID. 34 | Currently, Nicolas is holds the list. → Pubish the list in the GitHub. 35 | 36 | ## Authentication via AuthToken 37 | SWP authentication at NWP, or NWPs among each other: OAuth with JWT?And OAuth2 refresh token? 38 | 39 | OAuth2 with Refresh Token: 40 | - Configuration at SWP: BillerID, 2 API-URLs, (one time) authentication code. 41 | - The IdP delivers a new refresh token with the auth token comes from time to time; validity period of the auth token can be configured in the IdP. 42 | - How can the purpose be specified? → to be clarified. 43 | - If AuthToken is not signed, IdP must always be contacted to verify validity. 44 | - The hurdle to implement OAuth is quite big for small SWPs. 45 | - The *sub* may contain e.g. the biller PID. 46 | 47 | → Eva will provide an overview of possible usages of OAuth. 48 | 49 | 50 | ## License model - Proposal for objectives, tasks and duties of SWP-API 51 | ### Goal 52 | - Promotion of a nationwide network for electronic invoices based on service providers for billers and bill recipients (Open API). 53 | - Compatibility between software packages for invoicing and service providers for invoice routing. 54 | - Compatibility between software packages for incoming invoice processing and service providers for invoice routing. 55 | - No distinction between B2C and B2B. 56 | 57 | ### The license should specifies 58 | - Management of source code and documentation 59 | → Who is the **owner**? 60 | - Publisher of changes/updates? → Who has the **right to change**? 61 | - Conditions for **contributions** 62 | - **Disclaimer** 63 | - **Warranty** resp. exclusion of warranty 64 | - **Copyright** → Yes, under this license 65 | - Private modifications → No, modifications have to be introduced via contributions. 66 | - Administrator of **network IDs** of billers, bill recipients, service providers. 67 | 68 | ### Commitments of usufruct 69 | - Obligation to implement updates within a certain period of time 70 | - Commitment to repond to a Look-Up request 71 | - Support of the network concept: Obligation to route invoices to connected invoice recipients (costs?) 72 | 73 | See [https://choosealicense.com/licenses/](https://choosealicense.com/licenses/) 74 | 75 | - Proposals for owner: 76 | -- GS1/SwissDigin 77 | -- New Foundation / association 78 | -- SWICO 79 | -- OpenPEPPOL 80 | - Further suggestion: Publish level 1 (B2C) of the SWP-API only with reference to future institutionalization → faster ready for implementation. BUT: License is open; owner will be determined afterwards. 81 | 82 | ## B2C und B2B formats 83 | - Proposal: Remove eBill format from the SWP-API because no SWP has implemented it yet and because it cannot be use for B2B. → Instead ZUGFeRD Basic-WL can be used, if ZUGFeRD Basic-WL can be converted to eBill. 84 | - **QR-PDF** (eBill) 85 | - Existing: **YB**, **EIXML** (only if SWP-API is licenced, see above) ; soon there will be changes there, like QR-IBAN, e-mail address etc.. 86 | Only with PDF/A-3 Hybrid 87 | - Currently rejected proposal: Swiss print format from Viscom 88 | -- XML with 40-60 fields, simple invoice with QR code. 89 | -- This could be a PDF file with XML file attachment ( ~ Proposal Mr. Messerli) [https://www.viscom.ch/?v=vi&name=news](https://www.viscom.ch/?v=vi&name=news) 90 | -- The question rather concerns the process: Where to pick up the data or PDF invoice in order to make a decision between printing or eBill? 91 | If the data is retrieved after rendering, then it's simply a QR-PDF and not a new format. 92 | If the biller delivers all the data, the decision between printing or eBill is done in the NWP where the Viscom XML is created for printing if no eBill is possible. 93 | - **ZUGFeRD EN16931**, **EXTENDED**, **Basic-WL** (→ Remo clarifies if it contains all to create an eBill?) 94 | - Main recommendation: **ZUGFeRD EN16931** 95 | 96 | ## Comments from Pierre Arnaud 97 | - „SIX should extend the ebill.xml so that it can hold all data provided by the QR invoice” 98 | _Sollen wir hier einen Vorschlag machen, oder lieber die Aufgabe der SIX überlassen?_ 99 | 100 | - Authentication – „ A standardized structure would be helpful” 101 | _Was ist hier gemeint?_ _JWT ist ein Standard. 102 | Oder meint Ihr, die Richtlinien sollen vorgeben, dass in "sub" z.B. immer der Biller ID stehen soll? 103 | Ich bleibe der Meinung, dass jeder NWP die Frage Identität selber abwickeln soll – wir haben z.B. schon ein JWT, dass von der Software über einen Crésus-eigenen OAuth2-Server bekommt. Vorzuschreiben, dass alle über einen von SIX gehosteten Server gehen müssen, ist problematisch: SIX müsste das Onboarding der Endkunden gewährleisten können…_ 104 | 105 | - Configuration at biller/SWP 106 | _Das macht viele Informationen, die der User eintippen oder über Copy-Paste einfügen muss. 107 | Sollen wir da ein JSON-Format spezifizieren, das in einem Schlag von der SWP-Software eingelesen werden kann? 108 | → Könnte als Antwort auf automatisches Onboarding dienen._ 109 | 110 | - Interconnect between NWPs 111 | _Ganz schön – da muss jedoch jemand ein zentrales Repository pflegen, damit das Routing der Rechnungen von einem NWP zum anderen gehen kann, auf Basis eines Payer IDs? Käme da also die SIX wieder in eine zentrale Rolle? Wenn ja, wäre das sicher mit Routing-Kosten verbunden sein. Wenn nein, muss jemand diese Rolle aufnehmen… und da möchte ich mich nicht mit den Fragen Datenschutz auseinander setzen müssen_ J 112 | 113 | ## One Format for B2C and B2Bs: ZUGFeRD (GS1) 114 | Last meeting we said: 115 | > - ZUGFeRD 2.0.1 (with swissness by GS1) corresponds to a subset of the Cross Industry Invoice (~200 fields) and is an EU standard (EN16931) 116 | > - **One** format for B2C and B2B: so, no need for biller/SWP to distinguish between B2C and B2B invoices. 117 | > - Not a big effort to implement on SWP; the largest effort for SWP is the implementation of the API, not in the preparation of the invoice format. 118 | > - Question: Is the format ZUGFeRD 2.0.1 with the EN16031 profile enough or are further ZUGFeRD profiles needed? For example, if no line items are available? 119 | 120 | - ZUGFeRD: Profiles *Basic* and *Minimum* can be ignored; only *Basic-WL* (without line items) for DE und FR, ***EN16931*** (Payment term, PID?, no installments!) and *EXTENDED* (discount, installments?) are relevant. 121 | - EU standard: only XML; ZUGFeRD "only" approved. For invoices to the public sector. 122 | - *Extended* is the extension of *EN16931*; *Basic-WL* is less. 123 | - Is whole addressing (e.g. BillerID) mapped in ZUGFeRD? 124 | 125 | ## API call to receive B2B invoices 126 | Two endpoints are needed for a B2B customer to receive invoices: 127 | 1. Get list of available new invoices 128 | `customers/{customerId}/business-cases` 129 | Similar to how the events are fetched. 130 | 2. Get content of one new invoice 131 | `customers/{customerId}/business-cases/${businessCaseId}` 132 | 133 | ## Interconnect 134 | Based on SWP-API / NWP-API: 135 | - RS makes RE lookup at the NWP via e-mail, PID (41xx) or UID. 136 | - With PID you know which NWP has the RE. 137 | - RS NWP routes the invoice to RE NWP (via SWP-API) 138 | - RE NWP sends invoice to RE (B2B) 139 | - Disadvantages: 140 | -- No supply chain messages 141 | -- Specific to Switzerland 142 | -- Exact definition still needed 143 | - Advantages 144 | -- Simple 145 | 146 | With OpenPEPPOL: 147 | - Directory to find RS, incl. formats, URL of RS; Owner is an EU office 148 | - RS talks to access point (= NWP) 149 | - Access point → Access point → RE 150 | - Advantage: 151 | -- Supply Chain Messages 152 | -- Standard EN16931 153 | -- Already defined 154 | - Disadvantage: 155 | -- UBL 156 | 157 | ## Next steps 158 | - Define stage 1 (B2C) and send it first to the small round (this working group) and aftwewards, to all NWPs for the "consultation process". 159 | - Discussion on API / biller id in event endpoints? What else? → Nicolas, Eva will clear this up. 160 | - Onboarding process in general. How to validate sensitive data, e.g. account number? 161 | - SWP config items: within a Json structure? 162 | 163 | ## Open questions / answers 164 | - SIX does not plan to implement a bulk search. 165 | 166 | ## Final note 167 | - Next meeting scheduled: no date fixed! 168 | - Agenda: see Next steps above 169 | -------------------------------------------------------------------------------- /documents/nwp-directory.md: -------------------------------------------------------------------------------- 1 | # NWP Directory 2 | 3 | ## List of PID prefixes 4 | 5 | Switzerland: 6 | | Prefix | Name | Company | 7 | |:------:|-------------|---------| 8 | | `4100` | Reserved | | 9 | | `4101` | SIX eBill Infrastructure and SIX Paynet | | 10 | | `4102-4108` | Claimed by SIX (4102 was used accidentally by SIX eBill infrastructure around the middle of 2019) | | 11 | | `4109` | AbaNet | Abacus | 12 | | `4110` | PostFinance B2B / SIX eBill for migrated B2C PostFinance customers | PostFinance/SIX | 13 | | `4111` | InvoCLOUD | | 14 | | `4112` | Crésus | Epsitec | 15 | | `4114` | Billte | | 16 | | `4130` | Conextrade | Swisscom | 17 | | `4140` | Pentag | | 18 | | `4141` | Avaloq Outline AG | | 19 | | `4142` | gate2b | io-market | 20 | | `4150` | Pentag (double entry for historical reasons) | | 21 | | `4170` | Crossinx | | 22 | | `4177` | Swiss Post Solutions | | 23 | | `4180` | Reserved, this range could be used later for 6-digit NWP IDs. | | 24 | | : | | | 25 | | `4199` | | | 26 | 27 | Germany: 28 | | Prefix | Name | Company | 29 | |:------:|-------------|---------| 30 | | `4970` | Crossinx | | 31 | -------------------------------------------------------------------------------- /documents/nwpstatus.md: -------------------------------------------------------------------------------- 1 | # NWP status 2 | 3 | Here's a list of all known participating NWPs. 4 | 5 | - Abacus: In beta, ready for additional beta customers 6 | - Epsitec: In planning 7 | - InvoCLOUD/Nintu: In production 8 | 9 | 10 | 11 | NWPs who wish to change their status: Please get in contact with one of the admins. 12 | -------------------------------------------------------------------------------- /documents/onboarding.md: -------------------------------------------------------------------------------- 1 | # Biller Onboarding 2 | 3 | A biller should be able to easily configure her software and specify all parameters 4 | required to communicate with the API. 5 | 6 | ## JSON format 7 | 8 | File `onboarding-sample.json` provides an example JSON payload used to configure 9 | the client software with its initial parameters. 10 | 11 | Here is a subset of the JSON file: 12 | 13 | ```json 14 | { 15 | "version": "1.0", 16 | "is_test": false, 17 | 18 | "audience": "biller", 19 | "expiration_date": "2020-02-20T23:59:59+01:00", 20 | 21 | "party": { 22 | "id": "41090012345678938", 23 | ... 24 | }, 25 | "nwp": { 26 | "id": "4109", 27 | "api_endpoint": { 28 | "url": "https://api.mynwp.ch/biller/v1", 29 | ... 30 | } 31 | ... 32 | }, 33 | 34 | "auth": { 35 | "issuer": "https://auth.mynwp.ch", 36 | "authorization_endpoint": { 37 | "url": "https://auth.mynwp.ch/oauth/v1/initial", 38 | "headers": [], 39 | "params": { 40 | "code": "oaerhgergha0ghaergj", 41 | "grant_type": "authorization_code", 42 | "client_id": "https://ebill-swp.org", 43 | "redirect_uri": "tag:ebill-swp.org,2020:biller-onboarding" 44 | } 45 | }, 46 | 47 | "token_endpoint": { 48 | "url": "https://auth.mynwp.ch/oauth/v1/token", 49 | "headers": ["Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW"] 50 | } 51 | } 52 | } 53 | ``` 54 | 55 | ### `party` section 56 | 57 | The `party` section defines the target audience of this JSON file. In the sample, 58 | the audience is the `biller`, which is defined by its `id` (PID), `name` and 59 | additional settings. 60 | 61 | ### `nwp` section 62 | 63 | The `nwp` section defines the identity of the NWP and the API entry points used 64 | by the SWP to communicate with the NWP. 65 | 66 | - `nwp.id` ⇒ identifier of the NWP (please see `nwp-directory`). 67 | - `nwp.name` ⇒ name of the NWP (e.g. `SIX Paynet`). 68 | - `nwp.logo_url` ⇒ URL to PNG image used to represent the NWP in the SWP's UI. 69 | - `nwp.info_url` ⇒ URL to NWP landing page (for the end user). 70 | - `nwp.api_endpoint` ⇒ definition of the API endpoint (`url` and `headers` which 71 | should be provided with every call to the API, in addition to the `Authorization` 72 | header, which will be filled with a valid _access token_). 73 | 74 | ### `auth` section 75 | 76 | The `auth` section provides the information needed to complete the onboarding 77 | process. 78 | 79 | The SWP sends the initial authorization code to the _authorization endpoint_ 80 | provided by the NWP. The NWP replies with an initial _access token_ and 81 | _refresh token_. The refresh token can then be sent to the _token endpoint_ 82 | in order to request new tokens. 83 | 84 | - `auth.authorization_endoint` ⇒ defines how to talk to the authorization endpoint: 85 | - `url` ⇒ URL of the endpoint (always `https`, TLS 1.2 or higher). 86 | - `headers` ⇒ additional headers which should be included in the request. 87 | - `params` ⇒ set of key/value pairs which need to be sent in the body of the `POST` request, 88 | using the standard `application/x-www-form-urlencoded` encoding. This includes the `code` which 89 | is unique and can be used exactly once (*) until the expiration date has been reached. 90 | - `auth.token_endpoint` ⇒ defins how to talk to the token endpoint: 91 | - `url` ⇒ URL of the endpoint (always `https`, TLS 1.2 or higher). 92 | - `headers` ⇒ additional headers which should be included in the requests. 93 | 94 | > (*) Should we define restrictions to the use of the _authorization code_ (e.g. single use)? 95 | 96 | ## Example OAuth 2.0 flow 97 | 98 | ### Initial request 99 | 100 | Use the provided _authorization endpoint_ information to retrieve the initial 101 | access and refresh tokens: 102 | 103 | ```txt 104 | POST /auth/v1/initial HTTP/1.1 105 | Host: auth.mynwp.ch 106 | Content-Type: application/x-www-form-urlencoded 107 | 108 | code=oaerhgergha0ghaergj&grant_type=authorization_code&client_id=...&redirect_uri=... 109 | ``` 110 | 111 | ### Subsequent requests 112 | 113 | Use the _authorization_ and _refresh token_ retrieved by the initial request to 114 | fetch updated access and refresh tokens: 115 | 116 | ```txt 117 | POST /oauth/v1/token HTTP/1.1 118 | Host: auth.mynwp.ch 119 | Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW 120 | Content-Type: application/x-www-form-urlencoded 121 | 122 | grant_type=refresh_token&refresh_token=eyJhbGciO.eyJqdggSrg53.3rgSJC34ef 123 | ``` 124 | 125 | ### Responses (200 OK) 126 | 127 | The token requests return an opaque _access token_ which must be handed over to 128 | every API call. The _refresh token_ must be stored and/or updated for future calls. 129 | 130 | ```json 131 | { 132 | "access_token": "eyJhbGIJ9.eyJqdGkMTI1NH0.LcSaQy", 133 | "expires_in": 600, 134 | "refresh_token": "eyJhbGciO.eyJqdggSrg53.3rgSJC34ef" 135 | } 136 | ``` 137 | 138 | The access token returned by the NWP should be treated as an opaque string; it might 139 | or might not be a JWT. 140 | 141 | 142 | ### API call 143 | 144 | Use the _access token_ in the header _Authorization: Bearer_ of API calls: 145 | 146 | ```txt 147 | GET /biller/v1/healthcheck HTTP/1.1 148 | Host: api.mynwp.ch 149 | Authorization: Bearer eyJhbGIJ9.eyJqdGkMTI1NH0.LcSaQy 150 | Accept: application/json 151 | X-NWP-Foo: bar 152 | ``` 153 | or 154 | ```txt 155 | curl -X GET https://api.mynwp.ch/biller/v1/healthcheck -H 'Accept: application/json' \ 156 | -H 'Authorization: Bearer eyJhbGIJ9.eyJqdGkMTI1NH0.LcSaQy' -H 'X-NWP-Foo: bar' 157 | ``` 158 | 159 | ### API Responses (200 OK) 160 | 161 | The API call returns a json, e.g.: 162 | 163 | ```json 164 | { 165 | "message": "The healthcheck GET request was successfully received and processed.", 166 | "requestDateTime": "2020-05-04T13:02:25.889126+02:00", 167 | "receivedHeaders": [ 168 | { 169 | "headerName": "X-NWP-Foo", 170 | "headerValue": "bar" 171 | } 172 | ], 173 | "environmentStage": "X", 174 | "applicationVersion": "1.2.3", 175 | "apiVersion": "1.5.2" 176 | } 177 | ``` 178 | 179 | ## External Resources 180 | 181 | - OAuth 2.0 [Token Endpoint](https://tools.ietf.org/html/rfc6749#section-3.2) 182 | - OAuth 2.0 [Access Token Request](https://tools.ietf.org/html/rfc6749#section-4.1.3) and 183 | [Access Token Response](https://tools.ietf.org/html/rfc6749#section-4.1.4) 184 | - OAuth 2.0 [Refreshing an Access Token](https://tools.ietf.org/html/rfc6749#section-6) 185 | -------------------------------------------------------------------------------- /documents/swp-onboarding-sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "is_test": false, 4 | 5 | "audience": "biller", 6 | "expiration_date": "2020-02-20T23:59:59+01:00", 7 | 8 | "party": { 9 | "id": "41090012345678938", 10 | "name": "Muster AG", 11 | "is_sender": true, 12 | "is_receiver": false, 13 | "is_b2b_sender": false, 14 | "is_b2b_receiver": false 15 | }, 16 | 17 | "nwp": { 18 | "id": "4199", 19 | "name": "My NWP", 20 | "logo_url": "https://www.mynwp.ch/about/logo.png", 21 | "info_url": "https://www.mynwp.ch/about/info/", 22 | "api_endpoint": { 23 | "url": "https://api.mynwp.ch/biller/v1", 24 | "headers": ["X-NWP-Foo: bar"] 25 | } 26 | }, 27 | 28 | "auth": { 29 | "issuer": "https://auth.mynwp.ch", 30 | "authorization_endpoint": { 31 | "url": "https://auth.mynwp.ch/oauth/v1/initial", 32 | "headers": [], 33 | "params": { 34 | "code": "oaerhgergha0ghaergj", 35 | "grant_type": "authorization_code", 36 | "client_id": "https://ebill-swp.org", 37 | "redirect_uri": "tag:ebill-swp.org,2020:biller-onboarding" 38 | } 39 | }, 40 | 41 | "token_endpoint": { 42 | "url": "https://auth.mynwp.ch/oauth/v1/token", 43 | "headers": ["Authorization: Bearer czZCaGRSa3F0MzpnWDFmQmF0M2JW"] 44 | } 45 | } 46 | } 47 | --------------------------------------------------------------------------------