Folder Service
This section aims to help you implement your service that will interact with Algoan's Folder manager.
Code sections have been written in JavaScript and can be implemented with NodeJS. Of course, you are free to choose your favorite language.
It uses KoaJS library, a NodeJS HTTP framework, and superagent which is a HTTP client request library.
List of supporting documents to provide
More details are available in the Folder management section.
To start the folder process, Algoan needs to know which supporting documents the applicant has to upload.
Indeed, depending on the information given by the applicant, the list of required documents may be different. For example, for an applicant who is an employee, you might want pay stubs which can't be asked to someone who is retired.
Example
Subscribed event: kyc_documents_list_required
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const request = require('superagent');
const app = new Koa();
const router = new Router();
// This URL is just an example, you can of course create your own one
const resthookUrl = '/v1/resthook/example';
const algoanBaseUrl = 'https://api.algoan.com/v1';
/**
* Definition of your API
*/
async function postResthook(ctx) {
const requestBody = ctx.request.body;
const eventName = requestBody.subscription.eventName;
const payload = requestBody.payload;
// We suppose that eventName is defined
if (eventName === 'kyc_documents_list_required') {
const applicationId = payload.applicationId;
const folderId = payload.folderId;
// Get the application to generate the proper list of supporting documents
const application = await request.get(
`${algoanBaseUrl}/applications/${applicationId}`
);
/**
* Retrieve the list of documents from the bank partner.
* Convert it to Algoan format
*/
const supportingDocuments = await request.get(...);
const algoanSupportingDocuments = [
{
category: 'PROOF_OF_IDENTITY',
holder: 'APPLICANT',
partnerId: 'PARTNER_RANDOM_ID',
validFileTypes: ['ID_CARD', 'PASSPORT', 'DRIVING_LICENSE'],
required: true
}
];
if (
application.applicant.professionalSituation.businessSector === 'private'
) {
// Ask for the 3 last pay stub
algoanSupportingDocuments.push({
category: 'PROOF_OF_INCOMES',
holder: 'APPLICANT',
partnerId: 'PARTNER_RANDOM_ID',
validFileTypes: ['PAY_STUB'],
required: true,
period: {
count: 3,
unit: 'MONTH',
},
});
} else if (
application.applicant.professionalSituation.businessSector === 'retired'
) {
algoanSupportingDocuments.push({
category: 'PROOF_OF_INCOMES',
holder: 'APPLICANT',
partnerId: 'PARTNER_RANDOM_ID',
validFileTypes: ['PENSION_DISTRIBUTION_STATEMENT'],
required: true,
});
}
const url = `${algoanBaseUrl}/folders/${folderId}/supportingDocuments`;
const headers = { Authorization: `Bearer ${serviceAccountAccessToken}` };
await request.post(url)
.set(headers)
.send(algoanSupportingDocuments);
}
}
app.use(bodyParser());
router.post(resthookUrl, postResthook);
app.use(router.routes());
app.listen(3000);
File analysis
More details are available in the Folder management section.
In this example, the applicant will upload the front side of its identity card.
Example
Subscribed event: kyc_file_uploaded
const Koa = require('koa');
const router = require('koa-router');
const bodyParser = require('koa-bodyparser');
const binaryParser = require('superagent-binary-parser');
const request = require('superagent');
const app = new Koa();
const router = new Router();
// This URL is just an example, you can of course create your own one
const resthookUrl = '/v1/resthook/example';
const algoanBaseUrl = 'https://api.algoan.com/v1';
/**
* Definition of your API
*/
async function postResthook(ctx) {
const requestBody = ctx.request.body;
const eventName = requestBody.subscription.eventName;
const payload = requestBody.payload;
if (eventName === 'kyc_file_uploaded') {
const folderId = payload.folderId;
const supportingDocumentId = payload.supportingDocumentId;
const fileId = payload.file.id;
const apiUrl = payload.file.url;
// NOTE: apiUrl === fileAPIUrl
const fileAPIUrl = `${algoanBaseUrl}/folders/${folderId}/supporting-documents/${supportingDocumentId}/files/${fileId}`;
// Get a signedUrl to download the file
const file = await request.get(fileAPIUrl);
// file =
// {
// ...
// "signedUrl": "https://storage.googleapis.com/example-bucket/cat.jpeg?...",
// "signedUrlTTL": 3600
// }
// More details on file properties: https://developers.algoan.com/api/#operation/postFile
// Download the file with the signedUrl
const file = await request.get(file.signedUrl)
.parse(binaryParser)
.buffer();
// Send the file to the identify verification service
// Get the OCR result and convert it to Algoan format
const identityResult = await request.post(...);
// Algoan PATCH /files request body
const reqBody = {
type: 'ID_CARD_FRONT',
status: 'OK',
properties: {
firstName: 'John',
lastName: 'Doe',
birthDate: '1999-01-01',
expiredAt: '2022-03-12',
nationality: 'FR',
mrzLines: [
'P<RUSMALBORSKYI<<KOVBOJ<<<<<<<<<<<<<<<<<<<<<',
'7553279419RUS8712242M2104131<<<<<<<<<<<<<<02',
],
civility: 'MR',
deliveredAt: '2012-03-12',
},
internalComments: [
{
content: 'La carte d\'identité est valide',
}
]
}
const url = `${BASE_URL}/folders/${folderId}/supportingDocuments/`;
const headers = { Authorization: `Bearer ${serviceAccountAccessToken}` };
await request.patch(url)
.set(headers)
.send(reqBody);
}
}
app.use(bodyParser());
router.post(resthookUrl, postReshook);
app.use(router.routes());
app.listen(3000);
Document collected from an external UI
More details are available in the Folder management section.
When a process is handled by an external User Interface, two events are sent in order to start and finish the process.
The following example will describe the case of a face matching process.
Redirect the applicant to the Identity Verification Service
Example
Subscribed event: face_matching_link_required
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const request = require('superagent');
const app = new Koa();
const router = new Router();
// This URL is just an example, you can of course create your own one
const resthookUrl = '/v1/resthook/example';
const algoanBaseUrl = 'https://api.algoan.com/v1';
/**
* Definition of your API
*/
async function postResthook(ctx) {
const requestBody = ctx.request.body;
const eventName = requestBody.subscription.eventName;
const payload = requestBody.payload;
if (eventName === 'face_matching_link_required') {
const folderId = payload.folderId;
const supportingDocumentId = payload.supportingDocumentId;
// Get the redirection URL from the identity verification service
const providerRedirectUrl = await request.get(...);
// Algoan PATCH /supporting-documents request body
const reqBody = {
redirectUrl: providerRedirectUrl,
}
const url = `${BASE_URL}/folders/${folderId}/supportingDocuments/${supportingDocumentId}`;
const headers = { Authorization: `Bearer ${serviceAccountAccessToken}` };
await request.patch(url)
.set(headers)
.send(reqBody);
}
}
app.use(bodyParser());
router.post(resthookUrl, postResthook)
app.use(router.routes());
app.listen(3000);
Face matching results
Example
Subscribed event: face_matching_completed
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const request = require('superagent');
const app = new Koa();
const Router = new Router();
// This URL is just an example, you can of course create your own one
const resthookUrl = '/v1/resthook/example';
const algoanBaseUrl = 'https://api.algoan.com/v1';
/**
* Definition of your API
*/
async function postResthook(ctx) {
const requestBody = ctx.request.body;
const eventName = requestBody.subscription.eventName;
const payload = requestBody.payload;
if (eventName === 'face_matching_completed') {
const folderId = payload.folderId;
const supportingDocumentId = payload.supportingDocumentId;
// Get results from the identity verification service
const faceMatchingResults = await request.get(...);
// You can also optionally send us a result file
const fileToUpload = await request.get(...);
const url = `${BASE_URL}/folders/${folderId}/supportingDocuments/${supportingDocumentId}/files`;
const headers = {
Authorization: `Bearer ${serviceAccountAccessToken}`,
'Content-Type': 'multipart/form-data',
};
// POST the file with its result to Algoan
await request.post(url)
.set(headers)
.attach('file', fileToUpload)
.field('status', 'OK')
.field('properties', { score: 1 });
}
}
app.use(bodyParser());
router.post(resthookUrl, postResthook);
app.use(router.routes());
app.listen(3000);
Final decision
More details on this part in the Folder management section.
When the applicant has uploaded all his required documents and Algoan considers the Folder ready to be sent, a final decision is necessary in order to continue the process.
Example
Subscribed event: kyc_folder_validation_required
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const request = require('superagent');
const app = new Koa();
const router = new Router();
// This URL is just an example, you can of course create your own one
const resthookUrl = '/v1/resthook/example';
const algoanBaseUrl = 'https://api.algoan.com/v1';
/**
* Definition of your API
*/
async function postResthook(ctx) {
const requestBody = ctx.request.body;
const eventName = requestBody.subscription.eventName;
const payload = requestBody.payload;
// We suppose that eventName is defined
if (eventName === 'kyc_folder_validation_required') {
const folderId = payload.folderId;
// Get the entire folder
const application = await request.get(
`${algoanBaseUrl}/folders/${folderId}`
);
/**
* Get the result from the partner and convert it to Algoan Format
*/
const finalDecision = await request.get(...);
const url = `${algoanBaseUrl}/folders/${folderId}`;
const headers = { Authorization: `Bearer ${serviceAccountAccessToken}` };
await request.patch(url)
.set(headers)
.send({
state: 'ACCEPTED'
});
}
}
app.use(bodyParser());
router.post(resthookUrl, postResthook);
app.use(router.routes());
app.listen(3000);