Skip to content

Commit

Permalink
feat: Initial draft of BNPL Arazzo and OpenAPI documents (#209)
Browse files Browse the repository at this point in the history
* feat: Initial draft of BNPL Arazzo and OpenAPI documents

* chore: Removed Visual Studio Code settings

* chore: Added OR condition in successCriteria as suggested

Co-authored-by: Frank Kilcommins <[email protected]>

* refactor: Move Parameter to Request Body Objects and added missed property in OpenAPI description

---------

Co-authored-by: Frank Kilcommins <[email protected]>
  • Loading branch information
SensibleWood and frankkilcommins authored Jul 3, 2024
1 parent 95177d1 commit 91fec40
Show file tree
Hide file tree
Showing 3 changed files with 713 additions and 6 deletions.
6 changes: 0 additions & 6 deletions .vscode/settings.json

This file was deleted.

256 changes: 256 additions & 0 deletions examples/1.0.0/bnpl-arazzo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
arazzo: 1.0.0
info:
title: BNPL Workflow description
version: 1.0.0
sourceDescriptions:
- name: BnplApi
url: https://raw.githubusercontent.com/OAI/Arazzo-Specification/main/examples/1.0.0/bnpl-openapi.yaml
type: openapi
workflows:
- workflowId: ApplyForLoanAtCheckout
summary: Apply for a loan at checkout using a BNPL platform
description: Describes the steps to secure a loan at checkout from a BNPL platform. It is a multistep process that requires multiple API calls across several API providers to be completed successfully.
inputs:
type: object
required:
- customer
- products
properties:
customer:
description: |
Customer can either be the customer details, which will be used for enrollment, or a link to an existing customer resource as the customer already uses the BNPL platform
oneOf:
- type: object
required:
- firstName
- lastName
- dateOfBirth
- postalCode
properties:
firstName:
description: First name of customer
type: string
minLength: 1
maxLength: 70
lastName:
description: Last name of customer
type: string
minLength: 1
maxLength: 70
dateOfBirth:
description: Customer date of birth
type: string
format: date-time
postalCode:
description: Zip code or postal code of customer
type: string
minLength: 1
maxLength: 70
additionalProperties: false
- type: object
required:
- uri
properties:
uri:
description: URI that points to an existing customer resource, as customer already enrolled on platform
type: string
format: uri
additionalProperties: false
products:
type: array
minItems: 1
items:
type: object
required:
- productCode
- purchaseAmount
properties:
merchantCategoryCode:
description: Merchant category code of merchant. Only required for marketplace ecommerce platforms
type: string
pattern: '^[0-9]{4}$'
productCode:
description: Product code for loan application. Required for eligibility check
type: string
purchaseAmount:
description: Product purchase amount and currency code
type: object
required:
- currency
- amount
properties:
currency:
description: Currency code
type: string
pattern: "^[A-Z]{3}$"
amount:
description: Amount
type: number
steps:
- stepId: checkLoanCanBeProvided
description: |
Call the BNPL API to filter the basket for products qualifying for checkout loans. Pass in the array of products from the workflow input as the payload for the API call.
Act on the response payload:
- If a list of qualifying products is returned then submit customer choices.
- If the list of qualifying products is empty then end the workflow
operationId: findEligibleProducts
requestBody:
contentType: application/json
payload: |
{
"customer": "{$inputs.customer}",
"products": "{$inputs.products}"
}
successCriteria:
- condition: $statusCode == 200
onSuccess:
- name: existingCustomerNotEligible
type: end
criteria:
- condition: $statusCode == 200
- condition: $response.body.existingCustomerNotEligible == false
- name: qualifyingProductsFound
type: goto
stepId: getCustomerTermsAndConditions
criteria:
- condition: $statusCode == 200
- context: $response.body
type: jsonpath
condition: $[?count(@.products) > 0]
- name: qualifyingProductsNotFound
type: end
criteria:
- condition: $statusCode == 200
- context: $response.body
type: jsonpath
condition: $[?count(@.products) == 0]
outputs:
eligibilityCheckRequired: $response.body.eligibilityCheckRequired
eligibleProducts: $response.body.products
totalLoanAmount: $response.body.totalAmount
- stepId: getCustomerTermsAndConditions
description: |
Get the terms and conditions for the BNPL loans. This is static data and therefore has no arguments.
The data will be displayed to the customer and they'll accept the terms out-of-band.
After this step the flow will need to do a customer eligibility check if required.
operationId: getTermsAndConditions
successCriteria:
- condition: $statusCode == 200
onSuccess:
- name: eligibilityCheckRequired
type: goto
stepId: createCustomer
criteria:
- condition: $steps.checkLoanCanBeProvided.outputs.eligibilityCheckRequired == true
- name: eligibilityCheckNotRequired
type: goto
stepId: initiateBnplTransaction
criteria:
- condition: $steps.checkLoanCanBeProvided.outputs.eligibilityCheckRequired == false
outputs:
termsAndConditions: $response.body
- stepId: createCustomer
description: |
Call the BNPL platform and verify the customer is eligible for the loan, which creates a customer resource. This step is skipped if the customer is already enrolled in the BNPL platform.
Accepting the terms and conditions is set to true as the assumption is they have been accepted when this step is invoked.
If the customer is eligible for the BNPL loan then a customer resource is created
operationId: createCustomer
requestBody:
contentType: application/json
payload: |
{
"firstName": "{$inputs.customer.firstName}",
"lastName": "{$inputs.customer.lastName}",
"dateOfBirth": "{$inputs.customer.dateOfBirth}",
"postalCode": "{$inputs.customer.postalCode}"
"termsAndConditionsAccepted": true
}
successCriteria:
- condition: $statusCode == 200 || $statusCode == 201
onSuccess:
- name: customerIsEligible
type: goto
stepId: initiateBnplTransaction
criteria:
- condition: $statusCode == 201
- name: customerIsNotEligible
type: end
criteria:
- condition: $statusCode == 200
outputs:
customer: $response.body.links.self
- stepId: initiateBnplTransaction
description: Initiate the BNPL transaction by sending the customer identifier, eligible products, and indicative loan amount to initiate the loan process
operationId: createBnplTransaction
requestBody:
contentType: application/json
payload: |
{
"enrolledCustomer": "{$inputs.customer.uri}",
"newCustomer": "{$steps.createCustomer.outputs.customer}",
"products": "{$steps.checkLoanCanBeProvided.outputs.eligibleProducts}"
}
successCriteria:
- condition: $statusCode == 202
onSuccess:
- name: CustomerAuthorizationRequired
type: goto
stepId: authenticateCustomerAndAuthorizeLoan
condition: $response.body.redirectAuthToken != null
- name: CustomerAuthorizationNotRequired
type: goto
stepId: retrieveFinalizedPaymentPlan
condition: $response.body.redirectAuthToken == null
outputs:
redirectAuthToken: $response.body.redirectAuthToken
loanTransactionResourceUrl: $response.body.links.self
- stepId: authenticateCustomerAndAuthorizeLoan
description: |
Authenticate the customer and seek authorization for the loan.
Notes:
- Authenticate in this case does not necessarily mean with a valid set of credentials. It could be to prove the identity of the end user, possibly doing an UMA style interaction (which is too complex to tie into this example).
- A redirect is returned for to be sent to the customer. The customer should follow this, but the success of the authorisation is out-of-band.
- This flow mimics OAuth style authorization but is not an exact match as it does not rely on an authorisation code/access token exchange (as this seems somewhat artificial in this context).
operationId: getAuthorization
parameters:
- name: redirectAuthToken
in: query
value: $steps.authenticateCustomerAndAuthorizeLoan.outputs.redirectAuthToken
successCriteria:
- condition: $statusCode == 302
outputs:
redirectUrl: $response.headers.Location
- stepId: retrieveFinalizedPaymentPlan
description: Retrieve finalized payment plan to show to customer once authorization is complete
operationId: retrieveBnplLoanTransaction
parameters:
- name: loanTransactionId
in: path
value: $steps.initiateBnplTransaction.outputs.loanTransactionId
successCriteria:
- condition: $statusCode == 200
outputs:
finalizedPaymentPlan: $response.body
- stepId: updateOrderStatus
description: Send update from eCommerce platform to indicate order fulfilled and loan is therefore active
operationId: updateBnplLoanTransactionStatus
parameters:
- name: loanTransactionId
in: path
value: $steps.initiateBnplTransaction.outputs.loanTransactionId
requestBody:
contentType: application/json
payload: { "loanStatus": "Completed" }
successCriteria:
- condition: $statusCode == 204
outputs:
finalizedPaymentPlan: $steps.retrieveFinalizedPaymentPlan.finalizedPaymentPlan
Loading

0 comments on commit 91fec40

Please sign in to comment.