# [Market] How to use Node.js Skeleton
This section explains an extensible approach to embed BNPL options to your (Market) platform with data sharing functionality. In this page, we adopt Skeleton model (Node.js) described in the previous section.
TIP
If you do not use data sharing function, then you can take even simpler approach! Please have a look at Market integration.
Here is the Skeleton repository: https://github.com/credify-pte-ltd/serviceX-market-skeleton-nodejs
Here is the sample repository: https://github.com/credify-pte-ltd/market-sample
Sample UI:
TIP
This is a sandbox environment for you to play around with our BNPL systems. If you need the production environment, please let us know (email: info@credify.one).
# 0. Preparation
If you have not set up a Market yet, please refer to Getting started - Set up.
Please make sure that you allow BNPL providers to access your scope schemas. In the sandbox environment, you can test BNPL with BNPL provider
under Others
section as the following screenshot.
Also, please ensure you create API keys. To use BNPL, you need to grant claim_provider
to the API keys.
# 1. Set up the backend project
- Fork Node.js Skeleton service and clone it to your machine
Repository: https://github.com/credify-pte-ltd/serviceX-market-skeleton-nodejs
$ git clone https://github.com/your-account/serviceX-market-skeleton-nodejs.git
$ cd serviceX-market-skeleton-nodejs
$ yarn
- Set up
.env
$ cp .env.sample .env
Here is an example of .env
. More details are documented in the README.md of the Skeleton repository.
# database url
DATABASE_URL=postgres://user:password@postgres:5432/skeleton_nodejs
# `sandbox` or `production`
MODE=sandbox
# port to expose
PORT=8000
# organization ID you get on Dashboard
APP_ID=a0f9a736-ad97-d09b-abf7-d23ebca20bde
# your signing key you can see on Dashboard
APP_SIGNING_KEY=MC4aCZaWbPYDK2VwBBIEIOK3AJ5hzZ8s9YovNIa2dUmmEZ+PbpgeSfI+smahl0sJ
# your API key you can generate on Dashboard
APP_API_KEY=2pL9oQs10oI8LmN70Ip6OCDCkNmVZJ97JRnZRPy5NGeJgP00IkaBn21woWa0LcM
# profile keys that you provide. This should be same what you configure on Dashboard
APP_PROVIDING_BASIC_PROFILE=name,email,phone,address
Here is organization ID.
Here is a signing key. You need to provide a password to see the value. In the .env
, you need only the contents (e.g., MC4BCZaWbP...mahl0sJ
).
You can find basic profile information here. It's either phone
, name
, email
, and/or address
. This means that you will provide BNPL providers with these bits of information through serviceX. Your users will not have to provide these pieces of information again since you share them.
- Set up database
TIP
You can skip this section if you use docker compose.
Try docker-compose run
and visit http://localhost:8000/v1/demo-user
This project has a sample database integrated, so you can follow the below if you want to test the entire flow. In reality, you may want to use your own database or API call instead of having a dedicated database in this server.
# MacOS - run PostgreSQL in this default settings
$ brew services restart postgresql
# Create database
$ yarn db:create
# Run migration
$ yarn db:setup
# Generate seed data (This is demo purpose)
$ yarn db:seed:all
Let's test if it's working well with the following command.
$ yarn start
Open another tab and run this command.
$ curl "http://localhost:8000/v1/demo-user"
If you see database connection errors, please check database/config/config.js
.
# 2. Customize the backend project
All you have to change is dataInteraction/index.js
in the Skeleton project. Step #1~#7 are not BNPL specific. Step #8~#13 are very specific to BNPL integration.
- Customize
fetchUserClaimObject
What fetchUserClaimObject
does is following:
- Load a specified user
- This may be retrieved either from a local DB or from your internal API.
- In this documentation, the Skeleton service generates demo users by seed files. The User object is defined in
database/models/user.js
- Load commitments
- This is a secret value attached to each scope to be used when data receiving services validate the transmitted data is correct.
- The commitments should be generated during
pushClaims
process, namely insideupsertCommitments
function ofdataInteraction/index.js
.
- Form basic claim objects
- JSON keys have been already implemented. You just need to map the correct values to each JSON key.
- Form custom claim objects
- The following code is just a sample. You need to update it to reflect your custom claims.
First, you have to check this configuration on Dashboard.
Then you can see the scope details here. This information will be needed for JSON keys when forming claims.
// dataInteraction/index.js
const fetchUserClaimObject = async (db, localId, credifyId, includingScopes, withCommitments) => {
////
// NOTE: Please change this value according to what you have registered on Dashboard.
const scopeName = "a0f9a736-ad97-d09b-abf7-d23ebca20bde:loyalty-point-data-1653892708";
if (includingScopes.length === 0 || includingScopes.includes(scopeName)) {
claims[scopeName] = {
"a0f9a736-ad97-d09b-abf7-d23ebca20bde:amount-1653892708": user.loyaltyPoint,
"a0f9a736-ad97-d09b-abf7-d23ebca20bde:tier-1653892708": user.tier,
[`${scopeName}:commitment`]: commitments ? commitments[scopeName] : undefined,
}
}
////
}
- Complete
updateUserId
We will send you Credify ID to your systems. You need to keep the Credify ID associated with your internal ID.
- Complete
upsertCommitments
When you provide any data via Credify, you need to generate a certificate that says you have this data of this user. This certificate requires a commitment (a secret value). This commitment is used when data receiving parties validate the transmitted data is correct.
In this function, you are supposed to keep the provided commitments, so that you can retrieve the values whenever you need.
TIP
Once you are here, we recommend to deploy a server at this point because the frontend integration will need a remote API (offer filtering endpoint) instead of a localhost. That being said, the logic has been implemented already in the Skeleton service, so you can deploy it here. And then you can customize the following points thereafter.
If you test the server, using Heroku is the easiest. You can find how to deploy it to Heroku in Skeleton service's README.
- Customize
authenticateInternalUser
Some API endpoints will be called by your frontend, so these endpoints should have your own authentication logic. This function is to authenticate your internal users.
- Customize
authenticateInternalAPIClient
Some API endpoints will be called by your backend, so these endpoints should have your own authentication logic. This function is to authenticate your internal API clients.
- Register Webhook on Dashboard
Once you deploy the server, please register your webhook endpoints on Dashboard.
The default webhook endpoint of Skeleton service is
${your domain}/v1/webhook
- Complete
getBNPLCallback
Once BNPL transaction is completed, the BNPL provider will redirect the user back to this callback. This should return your callback URL. And also, you can add your own logic at this point.
- Implement
handleOrderStatusUpdate
When an order status changes, we call into your webhook endpoints. The default implementation of the Skeleton service will handle the webhook auth validation and call this function if it's related to order status update.
You may want to update the order status stored in your system.
- Implement
handleOrder
This function is called if you call [POST] /orders
successfully. You may want to store this order ID in your system for later use.
- Complete
fetchOrderCommitment
andupdateOrderCommitment
These functions handle commitment values related to an order. When you request a disbursement, you have to send disbursement requirement docs. The commitment values ensure the authenticity of the data.
- Implement
getCredifyId
This function returns Credify ID associated with a specified Order ID.
- Complete
saveDisbursementDocs
andfetchDisbursementDocs
These functions save/load disbursement requirement docs. The following object will be saved and loaded.
{
"invoice": "https://xx.com/invoce.pdf",
"down_payment": "https://xx.com/down_payment.pdf",
"first_payment": "https://xx.com/first_payment.pdf",
"delivery": "https://xx.com/delivery.pdf"
}
- Implement order management logic
Skeleton service provides order management API integration already through the following paths.
POST /orders
- Create an order object
GET /orders/credify/:id
- Get order status information
POST /orders/:id/cancel
- Cancel a specified approved order
You may want to call the endpoints listed above from your internal systems. For example, when you create a new order with POST /orders
, you will obtain order_id
. This property is required to check payment status later, so you should save this information in your systems. If you want to extend the API endpoints of this Skeleton service, please check v1/index.js
.
Disbursement requests should be made once BNPL providers confirm it's ready. This notification will be sent via webhook, so you may want to call disbursement API in the webhook handling process.
# 3. Configure user interface in your platform
To integrate with a market frontend, we provide three APIs that allow the frontend to authenticate users, display financial offers, and lodge user intent.
# Authenticate Users API:
API specs for auth API This API is used to authenticate users within the market frontend. It generates a new access token out of a provided API key with the same scopes.
# Show List of Financial Offers API:
API specs for offer list API This API is used to retrieve a list of evaluated offers that are available to a user based on their data and preferences. To use this API, a market partner must first authenticate the user with the "authenticateUser" API, then pass their data to this API to receive a list of offers that match the user's criteria. The response includes a list of evaluated offers along with details such as the offer ID, name, description, and the financial institution that is offering the product. This API is a key part of integrating Credify's services into a market's frontend.
# Lodge User Intent API:
API specs for lodge user API This API is used to lodge a new intent from a user on the market's platform for a specific financial product offer. This API requires authentication of the user and the market, and includes parameters such as the financial offer ID, user ID, and other relevant information related to the intent. Once the intent is lodged, it will trigger the process of evaluating the user's eligibility for the offer, and if eligible, the offer will be presented to the user for acceptance.
# 4. Handle status management and repayment
So far we see the flow of BNPL requests. Now that your users can authorize BNPL transactions. What's next to you is
- handle payment status
- request disbursement
- instruct users to repay
- Handle payment status
You will receive status update via webhook. When order status becomes approved, you can proceed with the next step, such as delivery of products. This handling should be implemented in handleWebhook
function in dataInteraction/index.js
.
- Request disbursement
You can see BNPL transaction list on Dashboard.
Once a transaction on your platform is done, you need to upload some documents to request disbursement. If you click on a Approved
order, you can see the following popup where you can upload documents.
Once uploading documents is done and BNPL provider confirms it's OK, our system will automatically request disbursement.
For some reason if your user wants to cancel a BNPL transaction (Approved order), you can request cancellation on the same popup.
- Instruct users to repay
We do not force users to install another app for BNPL. The users who enjoy BNPL can do everything inside your (Market) platform. We provide a function in SDK for your users to check necessary information.
- Swift
- Kotlin
- React.js
The following function opens BNPL related UI for your users to manage BNPL usage.
class SampleViewContoller: UIViewController {
///
func showBNPLDetail() {
passport.showDetail(
from: self,
user: user,
marketId: APP_ID,
productTypes: [.consumerBNPL]
) {
print("page dismissed")
}
}
}