Direct API (Biometric Pix)

❗️

Early preview of upcoming product

The following documentation is an early preview of Belvo's upcoming Biometric Pix product. As such:

  • Parameter key names, values, and structure may change before the final product is implemented.
  • Certain documentation (such as the instructions to download and setup the Belvo Payments Web SDK) is still in progress.

However, the general flow of information and required steps will not change.


With Belvo's Biometric Pix, collecting payments from users becomes seamless, removing the need for users to navigate to their financial institution to approve each individual payment request.

The first step in enabling biometric payment collection is to enroll the user’s device with their institution. During enrollment, key data about the device and the user's biometric information is securely registered with their institution, ensuring that future payments can be confirmed using biometric authentication alone.

Once enrollment is complete, you can start requesting payments directly from the user’s device.

In this guide, we’ll take you through each step, from device enrollment to successfully initiating a payment request.

Prerequisites

Enrollment

Enrollment is the process of registering a user’s device in their institution to allow for biometric payments for a given merchant. During the process, you will use a combination of the Belvo Payments Web SDK and API to retrieve key details about the device as well as the actual biometric signature.

Enrollment Flow

In the diagram below, you can see the overall enrollment flow.


  1. Your user selects the financial institution where they want to enroll their device (basically, the bank that they want to use to make biometric payments).
  2. Your application collects details about the user’s device (using the Belvo Payments Web SDK).
  3. You send these details to Belvo using Belvo’s API.
  4. The institution processes the device details and generates a unique URL for your user to be redirected to. Once they are redirected to their institution, they will provide their authorization for the enrollment and are then redirected back to your application.
  5. Once your user authorizes their device and your application, the institution generates a cryptographic challenge that is used to gather the user’s biometric data. Your will receive this challenge as a webhook notification and you will need to use the information in prompt your user to provide their biometric data (using the Belvo Payments Web SDK).
  6. After your user has provided their biometric data, you will need to send the encrypted information to the Belvo API do complete the enrollment process.
  7. Once the institution confirms the information, you will receive a webhook notification indicating that the enrollment was successful.

Enrolling a user device

📘

User and Customer Creation

Before you begin the enrollment process:

  • Make sure your user has an account with your application.
  • You have created a customer for your user using Belvo’s API.

To enroll a user’s device:

1️⃣ Prompt user for institution

In your widget, prompt your user to select the institution where they want to enroll the device in. Use the List all payment institutions request to get a list of all the possible institutions. Once the user selects the institution, save the id of the institution (required in the Begin enrollment step).


2️⃣ Collect Enrollment Information

In your application, initiate the collectEnrollmentInformation(accountTenure) method from the Belvo Payments Web SDK to collect the risk signals of the user’s device. The accountTenure must be the date that your user created an account with your application, in YYYY-MM-DD format.

// Method
collectEnrollmentInformation(accountTenure)

// Example
BelvoPaymentsAtoms.biometricPix.collectEnrollmentInformation("2023-06-23")

The collectEnrollmentInformation method will return an enrollmentInformation object. Save this as a JSON-compliant object as it will be required in the following step.

{
        deviceId: 'visitorUniqueId',
        osVersion: 'Unix 7.1.0',
        userTimeZoneOffset: '-03:00', 
        language: 'pt',
        screenDimensions: {
          height: 768,
          width: 1024
        },
        accountTenure: '2023-06-23'
}
{
    "deviceId": "visitorUniqueId",
    "osVersion": "Unix 7.1.0",
    "userTimeZoneOffset": "-03:00",
    "language": "pt",
    "screenDimensions": {
        "height": 768,
        "width": 1024
    },
    "accountTenure": "2023-06-23"
}

3️⃣ Begin enrollment

Once you have collected the enrollment information, you can begin the enrollment process with the user’s institution. You will need to make a POST Enroll a new user device request with the following payload:

In the response payload, you will receive a redirect_url that you need to display to your user (or redirect them automatically) so that they can be redirected to their institution to confirm their enrollment.

{
  "id": "82666cde-3f80-4350-b0f7-24cb8e9294c9",
  "created_by": "56689ef8-4c92-44ae-b2c1-60505da4a7e1",
  "created_at": "2024-11-26T11:20:57.389056Z",
  "updated_at": "2024-11-26T11:20:57.389056Z",
  "type": "open_finance_biometric_pix",
  "status": "PENDING",
  "details": {
    "status": "AWAITING_ACCOUNT_HOLDER_VALIDATION",
    "customer": "f78b14f3-5c1a-409a-966f-7b052b067cf0",
    "institution": "188716fb-39ad-44a7-a992-6c278d2b24a4",
    "platform": "BROWSER",
    "name": "First Enrollment",
    "callback_url": "https://example.com/enrollment-in-progress",
    "redirect_url": "https://www.user-banking-institituon.com/?enrollment_request=true...",
    "risk_signals": "*****"
  }
}
ParameterTypeDescriptionExample
idstringBelvo’s unique ID for the enrollment.82666cde-3f80-4350-b0f7-24cb8e9294c9
created_bystringThe Belvo ID of the merchant that created the enrollment.56689ef8-4c92-44ae-b2c1-60505da4a7e1
created_atstring (date-time)The ISO-8601 timestamp of when the data point was created in Belvo's database.2024-11-26T11:20:57.389056Z
updated_atstring (date-time)The ISO-8601 timestamp of when the enrollment was last updated.2024-11-26T11:20:57.389056Z`
typestringThe type of enrollment. For Biometric Pix, this must be set to open_finance_biometric_pix.open_finance_biometric_pix
statusstringThe status of the enrollment.PENDING
detailsobjectDetails regarding the Biometric Pix enrollment.-
details.statusstringThe status of the Biometric Pix enrollment. For details regarding the possible states, see our dedicated Enrollment Entity Model and States article.AWAITING_ACCOUNT_HOLDER_VALIDATION
details.customerstringThe Belvo customer.id you provided for the device enrollment.f78b14f3-5c1a-409a-966f-7b052b067cf0
details.institutionstringThe Belvo institution.id you provided for the device enrollment.188716fb-39ad-44a7-a992-6c278d2b24a4
details.platformstringThe device platform, as provided for the device enrollment.BROWSER
details.namestring (null)The human-readable name for the enrollment. This is useful for when you display all the enrollments your user has made using your application.My first enrollment
details.callback_urlstringThe URL to redirect your user to after the enrollment process is completed.https://example.com/enrollment-in-progress
details.redirect_urlstringThe URL you need to redirect your user to so that they can confirm the enrollment in their chosen institution.https://www.user-banking-institituon.com/?enrollment_request=true...
details.risk_signalsstringAn obfuscated string (******) used to indicate that risk signals have been provided.*****

4️⃣ Redirect your user

Redirect your user their institution so that they can confirm that enrollment process. During the process, they will need to log in to their institution, review the enrollment request, and then authorize the enrollment. Once the user authorizes the enrollment, the institution will redirect them back to your application.

📘

Once the user provides their authorization, the institution will begin evaluating the provided risk signals. Once accepted, the institution will generate a biometric challenge and Belvo will send a webhook with details.

5️⃣ Wait for Biometric Options webhook

Once the institution has accepted the risk signals and generated a biometric challenge, Belvo will send a webhook with the following payload:


{
  "webhook_id": "9994137d-f1d4-4c7f-8da3-4eb7a35a66bd",
  "webhook_type": "ENROLLMENTS",
  "webhook_code": "STATUS_UPDATE",
  "object_id": "69e93051-22cc-423f-b35d-2083e56e4320",
  "data": {
    "status": "PENDING",
    "metadata": null,
    "details": {
      "status": "AWAITING_ENROLLMENT"
    },
    "fido_options": { // Save this entire object as a JavaScript-compliant object
      "rp": {
        "id": "belvo.com",
        "name": "Belvo"
      },
      "user": {
        "id": "cba3fb04-5b0f-44c0-83d8-fed7db98d8d9",
        "name": "Mock User",
        "displayName": "Mock User"
      },
      "challenge": "R3JlZXRpbmdzIGZyb20gQmVsdm8h",
      "pubKeyCredParams": [
        {
          "alg": -7,
          "type": "public-key"
        }
      ],
      "timeout": 0,
      "excludeCredentials": [
        {
          "id": "AAABBB-ID",
          "type": "public-key"
        }
      ],
      "authenticatorSelection": {
        "authenticatorAttachment": "platform, cross-platform",
        "userVerification": "discouraged, preferred, required",
        "requireResidentKey": true,
        "residentKey": "111-ID"
      },
      "attestation": "none, indirect, direct, enterprise",
      "attestationFormats": [
        "packed, tpm, android-key, android-safetynet, fido-u2f, apple, none"
      ],
      "extensions": {
        "someAdditionalProp1": {}
      }
    }
  }
}

Once you receive the webhook, save the entire fido_options object (converted as a JavaScript-compliant object), as it will be used as the requestEnrollmentConfirmation(biometricRegistrationRequest) method.

6️⃣ Prompt for biometric data

In your application, use the requestEnrollmentConfirmation(biometricRegistrationRequest) to automatically prompt your user to provide their biometric details. The biometricRegistrationRequest object is the fido_options object you received in the webhook.

📘

Additional fields

You may receive additional fields in the fido_options object that are not included in the example below. However, just send through all the fields that you receive and our Web SDK will parse the required ones.

// Method
requestEnrollmentConfirmation(biometricRegistrationRequest)

// Example
BelvoPaymentsAtoms.biometricPix.requestEnrollmentConfirmation({
  rp: { id: 'belvo.com', name: 'Belvo' },
  user: { id: 'cba3fb04-5b0f-44c0-83d8-fed7db98d8d9', name: 'Mock User', displayName: 'My First Biometric User' },
  challenge: 'R3JlZXRpbmdzIGZyb20gQmVsdm8h',
  pubKeyCredParams: [{ alg: -7, type: 'public-key' }],
  attestation: 'direct',
  accountTenure: '2023-06-23'
}))

The requestEnrollmentConfirmation method will return an biometricRegistrationConfirmation object. Save this as a JSON-compliant object as it will be required in the following step.

{
    authenticatorAttachment: 'cross-platform',
    id: '447Q86f_XlFK0IBPVdf-giJUXs8pwmFCqqp0M3Q2PqM',
    rawId: 'base64',
    type: 'public-key'
    response: {
        attestationObject: 'YXR0ZXN0YXRpb25PYmplY3RFeGFtcGxlSGVyZQ==',
        clientDataJson: 'YXR0ZXN0YXRpb25PYmplY3RFeGFtcGxl'
    }
}
{
  "authenticatorAttachment": "cross-platform",
  "id": "447Q86f_XlFK0IBPVdf-giJUXs8pwmFCqqp0M3Q2PqM",
  "rawId": "base64",
  "type": "public-key",
  "response": {
    "attestationObject": "YXR0ZXN0YXRpb25PYmplY3RFeGFtcGxlSGVyZQ==",
    "clientDataJson": "YXR0ZXN0YXRpb25PYmplY3RFeGFtcGxl"
  }
}

7️⃣ Complete enrollment

Once you have the biometricRegistrationConfirmation object, you will need to make a POST Complete device enrollment request with the following payload:

// /payments/br/enrollments/{enrollment_id}/confirm/
{
  "confirmation_data": {
    "authenticatorAttachment": "cross-platform",
    "id": "WDNUd3Bpb3cwRlBsRUNySkcrbTZKbVpFNUQwZXRBSEM5OFF6K1RITHBlaz0=",
    "rawId": "X3Twpiow0FPlECrJG+m6JmZE5D0etAHC98Qz+THLpek=",
    "type": "public-key",
    "response": {
      "attestationObject": "YXR0ZXN0YXRpb25PYmplY3RFeGFtcGxlSGVyZQ==",
      "clientDataJSON": "YXR0ZXN0YXRpb25PYmplY3RFeGFtcGxl"
    }
  }
}

Belvo will respond with a 204 - No Content. The information is forwarded to the institution to complete the enrollment process.

8️⃣ Wait for the confirmation webhook

Once the institution confirms the enrollment, you will receive an ENROLLMENTS STATUS_UPDATE webhook indicating that the process is complete.

{
  "webhook_id": "9994137d-f1d4-4c7f-8da3-4eb7a35a66bd",
  "webhook_type": "ENROLLMENTS",
  "webhook_code": "STATUS_UPDATE",
  "object_id": "69e93051-22cc-423f-b35d-2083e56e4320",
  "data": {
    "status": "SUCCEEDED",
    "metadata": null,
    "details": {
      "status": "AUTHORIZED"
    }
  }
}

👍

With a confirmed enrollment, you can now begin to request payments!

Payments

Once you have completed an enrollment for a user device, you can start making payments requests. Biometric Pix payment requests use a combination of the Belvo Payments Web SDK and API.

Payment flow

In the diagram below, you can see the overall flow for a Biometric Pix payment.


  1. Your user selects a previously-authorized enrollment from which they want to make a payment.
  2. You create a Payment Intent, using the id of the enrollment. The institution generates a cryptographic challenge that is used to gather the user’s biometric data.
  3. Your application collects details about the user’s device and prompts for the user's biometric data (using the Belvo Payments Web SDK).
  4. You send through the collected details (using Belvo's API) to authorize the transaction. The institution will process the payments with the provided details.

Depending on the type of payment intent (immediate, scheduled, or recurring), you will receive webhook notifications regarding the status of the payment.

Making a payment

To make a Biometric Pix payment request:

1️⃣ Prompt user to choose enrollment

Use the List all enrollments API method to request all the enrollments your user has made using your application. Prompt your user to select the enrollment they want to use to make the payment. Save the id of that enrollment (used in the Create Payment Intent step).

2️⃣ Create a Payment Intent

With the enrollment.id, you can then make a POST request to /payments/br/payment-intents/ with the following payload:

 {
  "amount": "1234.12",
  "description": "Shoe payment",
  "statement_description": "Super Shoe Store - Brown Sneakers",
  "allowed_payment_method_types": [
    "open_finance_biometric_pix"
  ],
  "payment_method_details": {
    "open_finance_biometric_pix": {
      "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc",
      "enrollment": "82666cde-3f80-4350-b0f7-24cb8e9294c9",
    }
  },
  "confirm": true,
}

You will receive a 201 - Created response, with the following key objects:

{
  "payment_method_details": {
    "open_finance_biometric_pix": {
      "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc",
      "enrollment": "82666cde-3f80-4350-b0f7-24cb8e9294c9"
    }
  },
  "payment_method_information": {
    "open_finance_biometric_pix": {
      "provider_request_id": "d53af921-7be8-4513-a5a6-dd65746898ef",
      "fido_options": { // Save this object as a JavaScript-compliant object
        "challenge": "RXhhbXBsZUNoYWxsZW5nZUZvclBheW1lbnQ=",
        "timeout": 180000,
        "rpId": "belvo.com",
        "allowCredentials": [{ "id": "QUFBQkJCLUlE", "type": "public-key" }],
        "userVerification": "required",
        "extensions": {
          "someAdditionalProp1": {}
        }
      }
    }
  },
  "status": "REQUIRES_ACTION"
}

Once you receive the webhook, save the entire fido_options object (converted as a JavaScript-compliant object), as it will be used as the requestPaymentAuthorization(paymentRequestObject) method.

{
  "challenge": "RXhhbXBsZUNoYWxsZW5nZUZvclBheW1lbnQ=",
  "timeout": 180000,
  "rpId": "belvo.com",
  "allowCredentials": [{ "id": "QUFBQkJCLUlE", "type": "public-key" }],
  "userVerification": "required",
  "extensions": {
    "someAdditionalProp1": {}
  }
}
{
  challenge: 'RXhhbXBsZUNoYWxsZW5nZUZvclBheW1lbnQ=',
  timeout: 180000,
  rpId: 'belvo.com',
  allowCredentials: [{ id: 'QUFBQkJCLUlE', type: 'public-key' }],
  userVerification: 'required',
  extensions: {
    someAdditionalProp1: {}
  }
}


3️⃣ Collect Risk Signals and Prompt Biometric Challenge

To complete the payment request, in your application you will need to use the Belvo Payments Web SDK to:

  1. Collect the device risk signals: collectEnrollmentInformation(accountTenure).
  2. Prompt your user to provide their biometric scan: requestPaymentAuthorization(paymentRequestObject).

Collect Risk Signals

🚧

You must collect the risk signals for each payment intent request.

In your application, initiate the collectEnrollmentInformation(accountTenure) method from the Belvo Payments Web SDK to collect the risk signals of the user’s device. The accountTenure must be the date that your user created an account with your application, in YYYY-MM-DD format.

// Method
collectEnrollmentInformation(accountTenure)

// Example
BelvoPaymentsAtoms.biometricPix.collectEnrollmentInformation("2023-06-23")

The collectEnrollmentInformation method will return an enrollmentInformation object. Save this as a JSON-compliant object as it will be required in the following step.

{
        deviceId: 'visitorUniqueId',
        osVersion: 'Unix 7.1.0',
        userTimeZoneOffset: '-03:00', 
        language: 'pt',
        screenDimensions: {
          height: 768,
          width: 1024
        },
        accountTenure: '2023-06-23'
}
{
    "deviceId": "visitorUniqueId",
    "osVersion": "Unix 7.1.0",
    "userTimeZoneOffset": "-03:00",
    "language": "pt",
    "screenDimensions": {
        "height": 768,
        "width": 1024
    },
    "accountTenure": "2023-06-23"
}

Collect Biometric Data

In your application, initiate the requestPaymentAuthorization(biometricPaymentRequest) method from the Belvo Web SDK to prompt the biometric challenge on your users device. In the biometricPaymentRequest, provide the JavaScript-compliant fido_options object you received in the 201 Response from the Payment Intent request.

// Method
requestPaymentAuthorization(biometricPaymentRequest)

// Example
BelvoPaymentsAtoms.biometricPix.requestPaymentAuthorization({
  challenge: 'Y2hhbGxlbmdlMg==',
  timeout: 60000,
  rpId: 'bio.localhost',
  allowCredentials: [
    {
      id: 'X3Twpiow0FPlECrJG+m6JmZE5D0etAHC98Qz+THLpek=',
      type: 'public-key',
      transports: ['internal']
    }
  ],
  userVerification: 'preferred'
}
)

The requestPaymentAuthorization method will return a biometricAuthorization object. Save this as a JSON-compliant object as it will be required in the following step.

{
  id: "WDNUd3Bpb3cwRlBsRUNySkcrbTZKbVpFNUQwZXRBSEM5OFF6K1RITHBlaz0=",
  rawId: "X3Twpiow0FPlECrJG+m6JmZE5D0etAHC98Qz+THLpek=",
  response: {
    authenticatorData: "5KApO/fUiPm1wr+26+0W4DGfCJIhocf+sRR4PEKSdIoFAAAAAA==",
    clientDataJSON: "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWTJoaGJHeGxibWRsTWciLCJvcmlnaW4iOiJodHRwczovL2Jpby5sb2NhbGhvc3QiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
    signature: "MEUCIDK2IonpPp78LiQkFxl6w9lgSGpf8Zn2UaCdweE7d9DdAiEAyZIsMEUlVBIs0RNk4G2EVPaL8La+IBcUTSQZmIUcfBg=",
    userHandle: "dXNlcmlk"
  },
  type: "public-key"
}
{
  "id": "WDNUd3Bpb3cwRlBsRUNySkcrbTZKbVpFNUQwZXRBSEM5OFF6K1RITHBlaz0=",
  "rawId": "X3Twpiow0FPlECrJG+m6JmZE5D0etAHC98Qz+THLpek=",
  "response": {
    "authenticatorData": "5KApO/fUiPm1wr+26+0W4DGfCJIhocf+sRR4PEKSdIoFAAAAAA==",
    "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWTJoaGJHeGxibWRsTWciLCJvcmlnaW4iOiJodHRwczovL2Jpby5sb2NhbGhvc3QiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
    "signature": "MEUCIDK2IonpPp78LiQkFxl6w9lgSGpf8Zn2UaCdweE7d9DdAiEAyZIsMEUlVBIs0RNk4G2EVPaL8La+IBcUTSQZmIUcfBg=",
    "userHandle": "dXNlcmlk"
  },
  "type": "public-key"
}


4️⃣ Send through risk signals and biometric data

Once you have collected the enrollmentInformation and biometricAuthorization, make a POST Complete a Biometric Pix Payment Intent request with the following payload:

{
  "risk_signals": {}, // The enrollmentInformation object 
  "assertion": {}, // The biometricAuthorization object
}
{
  "risk_signals": {
    "deviceId": "visitorUniqueId",
    "osVersion": "Unix 7.1.0",
    "userTimeZoneOffset": "-03:00",
    "language": "pt",
    "screenDimensions": {
      "height": 768,
      "width": 1024
    },
    "accountTenure": "2023-06-23"
  },
  "assertion": {
    "id": "WDNUd3Bpb3cwRlBsRUNySkcrbTZKbVpFNUQwZXRBSEM5OFF6K1RITHBlaz0=",
    "rawId": "X3Twpiow0FPlECrJG+m6JmZE5D0etAHC98Qz+THLpek=",
    "response": {
      "authenticatorData": "5KApO/fUiPm1wr+26+0W4DGfCJIhocf+sRR4PEKSdIoFAAAAAA==",
      "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiWTJoaGJHeGxibWRsTWciLCJvcmlnaW4iOiJodHRwczovL2Jpby5sb2NhbGhvc3QiLCJjcm9zc09yaWdpbiI6ZmFsc2V9",
      "signature": "MEUCIDK2IonpPp78LiQkFxl6w9lgSGpf8Zn2UaCdweE7d9DdAiEAyZIsMEUlVBIs0RNk4G2EVPaL8La+IBcUTSQZmIUcfBg=",
      "userHandle": "dXNlcmlk"
    },
    "type": "public-key"
  }
}

ParameterTypeDescription
risk_signalsObjectThe JSON-compliantenrollmentInformation object you received using the collectEnrollmentInformation method.
assertionObjectThe JSON-compliant biometricAuthorization object your received using the requestPaymentAuthorization method.

You will receive a 204 - No Content response, indicating that the payload was forwarded to the user’s institution for confirmation.

5️⃣ Listen for Payment Intent status updates

Depending on whether you created an immediate, scheduled, or recurring payment intent, you will receive different notifications regarding the status of the payment intent.


👍

Done!

By following these steps, you have successfully created a Biometric Pix Payment Request!