# Extract Banking Data in Brazil (Widget) In this guide, we walk you through everything you need to extract banking data about your users from Brazil's Open Finance Network using our API. This includes: - An overview of the data flow - Setting up Belvo's Hosted Widget to connect your users. - Getting your user's data based on webhook events sent by Belvo. - Providing your users a way to manage their consents. ## Prerequisites Before you proceed with your integration, make sure that you have Gone through our getting started guide. In the getting started guide, you will create a Belvo account, generate some sandbox API keys, and set up a webhook URL. For testing purposes and developing your integration, we highly recommend using the Sandbox environment where possible. Additionally, for testing purposes and developing your integration, we highly recommend using the Sandbox environment along with the Mockbank institution. You can find example credentials to simulate different users for the Mockbank institution here. ## Data flow overview Belvo uses an *asynchronous workflow* to improve the extraction of data and your flow. As you can see from the diagram below, once your user has connected their account using the Hosted Widget and the link is created, Belvo loads all the data asynchronously and then notifies you using webhooks that the data is available for you to retrieve. ## Setting up the Hosted Widget Belvo's hosted widget is designed to simplify your development and integration process, is compliant with Open Finance regulations, and is constantly monitored by a team of specialists to improve the user experience. Our Hosted Widget can be embedded in your application as a *webview* and will guide your user through all the steps to grant their consent for you to access their data. This includes redirecting the user to their institution to provide consent and then back to your application. You can view a simplified flow of what happens during the widget connection process in the diagram below: Basically, whenever you want your user to connect their account from a financial institution in Brazil, you will need to: ### Generate a widget `access` token To be able to start the widget, you will need to first generate an `access` token using the following payload: Individual (CPF) ```shell Sandbox Request URL curl -X POST \ https://sandbox.belvo.com/api/token/ \ -H 'Content-Type: application/json' \ -d 'see example payload below' ``` ```json Widget Access Token (Individual - OFDA) { "id": "YOUR_SECRET_ID", "password": "YOUR_SECRET_PASSWORD", "scopes": "read_institutions,write_links,read_consents,write_consents,write_consent_callback,delete_consents", "stale_in": "300d", "fetch_resources": ["ACCOUNTS", "TRANSACTIONS", "OWNERS", "BILLS", "INVESTMENTS", "INVESTMENT_TRANSACTIONS"], "widget": { "purpose": "Soluções financeiras personalizadas oferecidas por meio de recomendações sob medida, visando melhores ofertas de produtos financeiros e de crédito.", "openfinance_feature": "consent_link_creation", "callback_urls": { "success": "your-url-here://success", "exit": "your-url-here://exit", "event": "your-url-here://error" }, "consent": { "terms_and_conditions_url": "https://www.your_terms_and_conditions.com", "permissions": ["REGISTER", "ACCOUNTS", "CREDIT_CARDS", "CREDIT_OPERATIONS"], "identification_info": [ { "type": "CPF", "number": "76109277673", "name": "Ralph Bragg" } ] }, "branding": { "company_icon": "https://mysite.com/icon.svg", "company_logo": "https://mysite.com/logo.svg", "company_name": "ACME", "company_terms_url": "https://belvo.com/terms-service/", "overlay_background_color": "#F0F2F4", "social_proof": true, }, "theme": [] } } ``` Company (CNPJ) ```shell Sandbox Request URL curl -X POST \ https://sandbox.belvo.com/api/token/ \ -H 'Content-Type: application/json' \ -d 'see example payload below' ``` ```json Widget Access Token (Company - OFDA) { "id": "YOUR_SECRET_ID", "password": "YOUR_SECRET_PASSWORD", "scopes": "read_institutions,write_links,read_consents,write_consents,write_consent_callback,delete_consents", "stale_in": "300d", "fetch_resources": ["ACCOUNTS", "TRANSACTIONS", "OWNERS", "BILLS", "INVESTMENTS", "INVESTMENT_TRANSACTIONS"], "widget": { "purpose": "Soluções financeiras personalizadas oferecidas por meio de recomendações sob medida, visando melhores ofertas de produtos financeiros e de crédito.", "openfinance_feature": "consent_link_creation", "callback_urls": { "success": "your-url-here://success", "exit": "your-url-here://exit", "event": "your-url-here://error" }, "consent": { "terms_and_conditions_url": "https://www.your_terms_and_conditions.com", "permissions": ["REGISTER", "ACCOUNTS", "CREDIT_CARDS", "CREDIT_OPERATIONS"], "identification_info": [ { "type": "CPF", "number": "76109277673", "name": "Ralph Bragg" }, { "type": "CNPJ", "number": "50685362006773", "name": "Bragg Mechanics" } ] }, "branding": { "company_icon": "https://mysite.com/icon.svg", "company_logo": "https://mysite.com/logo.svg", "company_name": "ACME", "company_terms_url": "https://belvo.com/terms-service/", "overlay_background_color": "#F0F2F4", "social_proof": true, }, "theme": [] } } ``` | Parameter | Required | Description | | --- | --- | --- | | `id` | true | Replace `YOUR_SECRET_ID` with the secretID you generated in the Belvo dashboard. | | `password` | true | Replace `YOUR_SECRET_PASSWORD` with the secretPassword you generated in the Belvo dashboard | | `scopes` | true | The `scopes` parameter contains a list of permissions that allow your to create a link for the user. This is a required parameter and must be sent exactly as shown. | | `stale_in` | false | The `stale_in` parameter allows you to control for how long Belvo stores user-derived data. For more information, check out the stale_in section of our Data retention controls article. | | `fetch_resources` | true | In the `fetch_resources` parameter, you provide a list of resources that you want Belvo to asynchronously retrieve for the user. For OFDA, we recommend: `["ACCOUNTS", "TRANSACTIONS", "OWNERS", "BILLS", "INVESTMENTS", "INVESTMENT_TRANSACTIONS"]`. | | `widget.purpose` | true | In the `purpose` parameter, you can customize the messaging that is displayed to your user regarding for what use case you are requesting their data. For more information, check out the purpose section in our Hosted Widget (OFDA) guide. | | `widget.openfinance_feature` | true | The `openfinance_feature` parameter indicates that the end user will go through the OFDA flow. It must be set to `consent_link_creation` | | `widget.callback_urls` | true | In the `callback_urls` object, you **must** add links to where your user should be redirected to in the following cases: success (your user successfully connected their accounts) exit (your user exited the widget before they completed the process) event (an error occurred during the connection process)For more information, check out the callback_urls section in our Hosted Widget (OFDA) guide.Belvo will also send additional event information depending on the event. For more information, please make sure to check out the Handling callback events section of the Hosted Widget (OFDA) guide. | | `widget.consent` | true | The `consent` object is unique to the OFDA widget and must be sent through. In the `terms_and_conditions_url` parameter, you **must** provide a link to your company's terms and conditions. In the `permissions` parameter, you must pass through the following array of permissions: `["REGISTER", "ACCOUNTS", "CREDIT_CARDS", "CREDIT_OPERATIONS"]`. In the `identification_info` array, you need to provide the identification information of the user that you want to retrieve information for. The information that you provide here must match the information that the regulated institution has for the user (for example, for businesses, the CPF and name must be for a user with access to the business account). For individuals, you just need to provide the CPF and name. For businesses, you need to provide both the CPF and CNPJ information. For more information, check out the identification_info section of our Hosted Widget (OFDA) guide. | | `widget.branding` | true | In the `branding` object, you **must** add your: company_icon company_logo company_name company_terms_url.You can also optionally add a custom background color for when the widget opens, as well as disable Belvo's messaging regarding how many accounts have been connected.For more information about the branding and customization options of the widget, check out our dedicated guide. | | `widget.theme` | false | You can optionally add your brand colors to the widget using the `theme` parameter. For more information regarding where these colors will appear in the widget, check out the dedicated Add custom colors to the widget section of our Branding guide. | Additionally, check out our Generating an access_token section of our Hosted Widget (OFDA) guide. ```json Access Token Response Example { "refresh": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MjMzNDY1MDY5MiwiaWF0IjoxNzEyNTcwNjkyLCJqdGkiOiIxMDAxMTg4NDU4Y2M0ZTlhOThmMDA4MmU3MDU...", "access": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNzEyNTcxODkyLCJpYXQiOjE3MTI1NzA2OTIsImp0aSI6ImFiNjRmYjkyZmY1ZjQ0MTU4N2IwM2Y2MDJhMzhh..." // [!code highlight] } ``` ### Start the widget inside a webview Next, you will need to redirect your user to the widget in a webview inside your application: ```Text Hosted Widget URL https://widget.belvo.io/ ?access_token={access} &mode=webapp &locale=pt &access_mode=single &external_id=HJLSI-897809 ``` | Parameter | Required | Description | | --- | --- | --- | | `access_token` | true | Replace `access` with the access token you received. | | `mode` | true | For the OFDA hosted widget to function correctly for your users, you must set the mode query parameter to webapp. | | `locale` | true | For the OFDA hosted widget to function correctly for your users, you must set the locale query parameter to pt. | | `access_mode` | false | You can use the `access_mode` parameter to define which type of link you want to create (`single` or `recurrent`). By default, Belvo creates `recurrent` links. For more information regarding the different link types, see theLinks section of our Links and Institutions guide. | | `external_id` | highly recommended | You can add an additional identifier to be associated with the link in the Belvo database. The `external_id` that you provide: should be a unique ID for each user in your database. must be at least three characters long. can only be composed of letters, numbers, dashes (`-`), and underscores (`_`). cannot contain any personally identifiable information about the user (email, name, phone number, credit card number, and so on).For more details, see the Adding your own identifier section of our Link creation best practices guide. | Additionally, check out ourStarting the widget section of our Hosted Widget (OFDA) guide. ### Listen for the success event that will include the link `id`. Once your user finishes the widget flow, we will send you a `success` event to the URL you provided when generated the widget `access` token. This event will include the link `id` that you you will need to associated with your `external_id` in your database. This step requires some knowledge of handling redirects and their query parameters. For details regarding the events we send (and their format), see the Handling callback events section of our Hosed Widget (OFDA) guide. To aid your development, we've created guides on how to set up deep links and listen for events for the following platforms: - iOS (Swift) - Android (Kotlin) - React Native ### Wait for webhooks and retrieve data As Belvo utilizes an asynchronous workflow, once the link is created we automatically retrieve the last 12 months of historical data for the user that just connected their account. We notify you via webhook events once the data is extracted and you can retrieve it. For more details, see the Getting Data section. ## Getting Data Regardless if you use single or recurrent links, once your user completes the widget flow successfully, Belvo asynchronously retrieves the last 12 months of owner, account, transaction, bill, and investment data for the link (historical updates). Once we have extracted the data, we notify you using a webhook that the information is ready to be retrieved. If you are using recurrent links, Belvo will retrieve the updated information for the link according to your refresh rate (recurrent updates). Just like historical updates, we notify you using a webhook that the new information is ready to be retrieved. Link Creation and Data Limits When generating consent and creating the link, Belvo already consumes one operational limit of Owners, Accounts, Transactions, Bills, and Investments (to retrieve the historical data for your user). However, Belvo has implemented certain internal mechanisms to optimize the data retrieval limits. For more information, please see our dedicated Open Finance Network Limits (Brazil) article. Brazil's Open Finance Network sets monthly limits regarding how often you can retrieve data for a specific person or business. These operational limits are linked to a combination of: - the user's CPF or CNPJ - the API data you want to get (Owner, Account, Transaction, or Bill) - the Open Finance network certificate Once the monthly operational limit of API calls is reached, no more information can be retrieved for the CPF/CNPJ until the start of the next calendar month. However, Belvo has implemented optimizations to maximize the amount of data you can retrieve for your users according to your data needs. For more information, please see our dedicated Open Finance Network Limits (Brazil) article. ### Historical updates Below you can see the flow of data for both single and recurrent links once a link is created: Each time that you receive a webhook for a given resource (owners, accounts, transactions, or bills), you will need to make a GET call to that endpoint, using the link ID, to retrieve the information. #### Get Owner information Belvo will asynchronously retrieve the last 12 months **owner** data for your link and then send you a webhook once the information is ready to retrieve (see the webhook example below): ```json Owners Historical Update { "webhook_id": "aadf41a1fc8e4f79a49f7f04027ac999", "webhook_type": "OWNERS", // [!code highlight] "process_type": "historical_update", // [!code highlight] "webhook_code": "historical_update", "link_id": "2f8ca7a1-c28f-46f2-bb41-21633099a280", // [!code warning] "request_id": "4363b08b-51eb-4350-9c74-5df5ac92a7f6", "external_id": "your_external_id", "data": { "total_owners": 2 // Total number of owners } } ``` Once you receive the webhook, you just need to make the following GET Owners request to retrieve the data for the given link: ```curl GET Owner Information curl --request GET 'https://api.belvo.com/api/owners/?link={id}' \ -u SECRET_ID:SECRET_PASSWORD ``` | Parameter | Type | Required | Description | Example | | --- | --- | --- | --- | --- | | `id` | string | true | The `link_id` you receive in your `historical_update` notification. | `2f8ca7a1-c28f-46f2-bb41-21633099a280` | #### Get Account information Belvo will asynchronously retrieve the last 12 months of **account** data for your link and then send you a webhook once the information is ready to retrieve (see the webhook example below): ```json Accounts Historical Update { "webhook_id": "aadf41a1fc8e4f79a49f7f04027ac999", "webhook_type": "ACCOUNTS", // [!code highlight] "process_type": "historical_update", // [!code highlight] "webhook_code": "historical_update", "link_id": "2f8ca7a1-c28f-46f2-bb41-21633099a280", // [!code warning] "request_id": "4363b08b-51eb-4350-9c74-5df5ac92a7f6", "external_id": "your_external_id", "data": { "total_accounts": 5 // Total number of accounts found. } } ``` Once you receive the webhook, you just need to make the following GET Accounts request to retrieve the data for the given link: ```curl GET Account Information curl --request GET 'https://api.belvo.com/api/accounts/?link={id}' \ -u SECRET_ID:SECRET_PASSWORD ``` | Parameter | Type | Required | Description | Example | | --- | --- | --- | --- | --- | | `id` | string | true | The `link_id` you receive in your `historical_update` notification. | `2f8ca7a1-c28f-46f2-bb41-21633099a280` | #### Get Transaction information Belvo will asynchronously retrieve the last 12 months of **transaction** data for your link and then send you a webhook once the information is ready to retrieve (see the webhook example below): ```json Transactions Historical Update { "webhook_id": "aadf41a1fc8e4f79a49f7f04027ac999", "webhook_type": "TRANSACTIONS", // [!code highlight] "process_type": "historical_update", // [!code highlight] "webhook_code": "historical_update", "link_id": "2f8ca7a1-c28f-46f2-bb41-21633099a280", // [!code warning] "request_id": "4363b08b-51eb-4350-9c74-5df5ac92a7f6", "external_id": "your_external_id", "data": { "total_transactions": 19, // Total number of transactions found "total_inflow_transactions": 10, // Total number of inflow transactions "total_outflow_transactions": 9, // Total number of outflow transactions "first_transaction_date": "2017-01-03", // First transaction date "last_transaction_date": "2020-03-25" // Last transaction date } } ``` Once you receive the webhook, you just need to make the following GET Transactions request to retrieve the data for the given link: ```curl GET Transaction Information curl --request GET 'https://api.belvo.com/api/transactions/?link={id}' \ -u SECRET_ID:SECRET_PASSWORD ``` | Parameter | Type | Required | Description | Example | | --- | --- | --- | --- | --- | | `id` | string | true | The `link_id` you receive in your `historical_update` notification. | `2f8ca7a1-c28f-46f2-bb41-21633099a280` | #### Get Bill information Belvo will asynchronously retrieve the last 12 months **bill** data for your link and then send you a webhook once the information is ready to retrieve (see the webhook example below): ```json Bill Historical Update { "webhook_id": "aadf41a1fc8e4f79a49f7f04027ac999", "webhook_type": "BILLS", // [!code highlight] "process_type": "historical_update", // [!code highlight] "webhook_code": "historical_update", "link_id": "16f68516-bcbc-4cf7-b815-c500d4204e28", // [!code warning] "request_id": "4363b08b-51eb-4350-9c74-5df5ac92a7f6", "external_id": "your_external_id", "data": { "total_bills": 2 // Total number of bills } } ``` Once you receive the webhook, you just need to make the following GET Bills request to retrieve the data for the given link: ```curl GET Bill Information curl --request GET 'https://api.belvo.com/api/bills/?link={id}' \ -u SECRET_ID:SECRET_PASSWORD ``` | Parameter | Type | Required | Description | Example | | --- | --- | --- | --- | --- | | `id` | string | true | The `link_id` you receive in your `historical_update` notification. | `2f8ca7a1-c28f-46f2-bb41-21633099a280` | ### Recurrent updates If you are using recurrent links, you will receive webhook events according to the frequency you established with Belvo (daily, weekly, monthly, and so on). Belvo sends the following webhook events for updates: - `new_owners_available` You will receive a `new_owners_available` webhook whenever we detect that there has been a change in account owners details. For more information, please see our dedicated Owners (Aggregation) webhook article. - `new_accounts_available` You will receive a `new_accounts_available` webhook whenever we detect that there has been a change in the accounts that the link has. For more information, please see our dedicated Accounts (Aggregation) webhook article. - `new_transactions_available` You will receive a `new_transactions_available` webhook whenever we detect that new transactions have occurred for any account the link has. For more information, please see our dedicated Transactions (Aggregation) webhook article. - `new_bills_available` You will receive a `new_bills_available` webhook whenever a new credit card bill statements has been generated for a billing period. For more information, please see our dedicated Bills (Aggregation) webhook article. As soon as you receive a webhook about newly updated information, you just need to make the same GET call as you did for the historical update to receive the updated information. ```shell # Retrieve owner data curl --request GET 'https://api.belvo.com/api/owners/?link={id}' # Retrieve account data curl --request GET 'https://api.belvo.com/api/accounts/?link={id}' # Retrieve transaction data curl --request GET 'https://api.belvo.com/api/transactions/?link={id}' # Retrieve bill data curl --request GET 'https://api.belvo.com/api/bills/?link={id}' ``` ### Other webhook events Belvo also notifies you when there are changes to your link's consent. You may receive the following webhooks relating to consents: - `openfinance_consent_expired` - `openfinance_consent_with_unrecoverable_resources` - `openfinance_consent_with_temporarily_unavailable_resources` For the `openfinance_consent_expired` events, you can prompt your user to renew their consent using the My Belvo Portal. For more information, please see our dedicated Consent webhook article. ## Adding a link to My Belvo Portal Regulatory Requirement According to Open Finance regulations, your users must have an easy-to-access way of managing their consents within your application or website. Belvo has created the My Belvo Portal (MBP) that allows users to manage their consents in a simple and straightforward way, meeting all the requirements of the regulations. In your application, you must include a clearly visible link to the MBP for your users to manage their consents. The MBP can be set up in three different ways: - Public MBP On Belvo's website, we host a universal instance of the MBP that any user can use to manage their consents. This instance consolidates all the consents they have granted using Belvo's OFDA product. You simply need to redirect your user to `https://meuportal.belvo.com/?mode=landing`, where they can input their details. Your user will be able to see **all** the consents they’ve granted using Belvo (including other applications using Belvo to extract data from Brazil's Open Finance Network). - Customized MBP You can customize the MBP to display only the consents that your user has granted your application, making it easier for them to manage the consents. - Consent Renewal Mode The MBP can also be used to renew an expired consent. Belvo will send you a webhook when one of your user's consent's has expired. Dedicated My Belvo Portal Guide For details on how to set up the My Belvo Portal in your application, see our dedicated My Belvo Portal (OFDA) guide. ## Additional resources ### Integration checklist We have created a dedicated checklist of all the things you should take into consideration when developing your OFDA integration. Check it out here: OFDA Integration Checklist. ### Open Finance Network Errors During the consent creation process, institutions in the Open Finance Network perform checks to ensure that the connection is stable and secure. If the institution determines that the connection is not stable or secure, it will redirect the user to a custom error page with the following content: *Ocorreu um error. Por favor, verifique o seu CPF or CNPJ para ter certeza de que está correto, feche o aplicativo e reinicie o processo para conectar sua conta.* And in the redirect URL, you will see a URL fragment with the following details: ``` api.belvo.com/api/consents/callback/#error_description=risk_analysis_denied... ``` This error can occur for the following reasons: - Your user has an active VPN connection on their device. We recommend turning the VPN off an trying again. - Your user is accessing their institution via their app on their mobile device, however, it is not the latest version of the app. Some institutions require that the app version is the latest possible version to allow for consent authorization. We recommend updating the institution app to the latest available version and trying again. - [**Itaú** **only**] Your user is accessing their institution on their desktop computer, however, they do not have Itaú's  Guardião 30 horas app installed on their computer. Itaú requires that users have this app installed on their desktop computer in order to perform the consent process.