# Direct API (Scheduled and Recurring Pix) With Belvo's Open Finance Payment Initiation (OFPI), you can collect **scheduled** payments from your customers and optimize their payment experience. In this guide, we’ll show you: - the general flow of data - how to create a payment intent to collect scheduled or recurring payments - the payment statuses and notifications - how to cancel scheduled or recurring payments Prerequisites Please make sure you have completed all the steps in our dedicated prerequisites article before continuing this guide. ## Data flow overview As you can see in the diagram below, the data flow for creating a scheduled or recurring payment involves: 1. Creating a payment intent (containing the required information for the payment to be processed in the Open Finance Network). 2. Listening for notifications regarding the scheduled payment. 3. On the day of the scheduled payment, listening for the `OBJECT_CREATED` webhook from the transactions resource. 4. Getting the transaction details when the payment is completed. For more details regarding the notifications you can receive as well as the lifecycle of a scheduled or recurring payment, please see the Payment statuses and notifications section of this guide. ## Create a scheduled Payment Intent The Payment Intent contains all the information necessary to register and process the payment in the Open Finance Network. To reduce friction for your customer, we recommend that you create your payment screen so that you can send all the information in just one **POST** call. To create a Scheduled or Recurring Payment Intent, you will need to make a POST Create a Payment Intent request with the following payload: With a previously created customer ```json With previously created customer { "amount": "1234.12", "description": "B23A-Shoe-Brown-Sneaker", "statement_description": "Super Shoe Store - Brown Sneakers", "allowed_payment_method_types": ["open_finance"], "external_id": "2c75c041-9cc7-430a-84e9-3b234aae76a2", "confirm": true, "payment_method_details": { "open_finance": { "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc", "payer_institution": "600f1b4a-1ef9-4f89-b341-1a35f0c32cc0", "callback_url": "https://www.acmecorp.com/checkout/3487321", "schedule": {} // see the dedicated sections below } }, "customer": "4714c93c-0132-4da4-b8fe-659515e1b1b6" } ``` With a new customer ```json With new customer { "amount": "1234.12", "description": "B23A-Shoe-Brown-Sneaker", "statement_description": "Super Shoe Store - Brown Sneakers", "allowed_payment_method_types": ["open_finance"], "confirm": true, "payment_method_details": { "open_finance": { "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc", "payer_institution": "600f1b4a-1ef9-4f89-b341-1a35f0c32cc0", "callback_url": "https://www.acmecorp.com/checkout/3487321", "schedule": {} // see the dedicated sections below } }, "customer": { "identifier": "10187609363", "name": "Caetano Veloso", "email": "caetano.veloso@musicabrazil.br", "phone": "+5511987654321", "address": "Rua de Caetano Veloso 432, 70200 Brasilia" }, } ``` | Parameter | Required | Description | | --- | --- | --- | | `amount` | true | The amount of the payment as a string. | | `description` | true | The description of the payment for your internal purposes. | | `statement_description` | optional (but recommended) | The description that will appear on the customer's bank statement (highly recommended). **Note**: If you do not use the `statement_description` parameter, the `description` value will be used as the statement description. | | `allowed_payment_method_types` | true | The `allowed_payment_method_types` parameter indicates which payment method should be used. For payments in Brazil, this must be set to `["open_finance"]`. | | `external_id` | optional (but recommended) | An additional unique identifier (UUID) for the resource for internal purposes. This can be useful for tracking the resource in your system and for debugging purposes. | | `confirm` | true | Indicates that the payment is ready for processing. | | `payment_method_details.open_finance` | true | In the `open_finance` object, you have to provide the following details about the payment: `beneficiary_bank_account`: The `id ` of the bank account that will receive the payment funds. `payer_institution`: The `id` of the institution from where the payment is made. `callback_url`: The URL that your user should be redirected to after approving the payment in their banking institution. `schedule`: See the dedicated sections below for details regarding each schedule you can request. `cpf`: (Only when the customer is a business) The CPF of the user that is making the payment. | | `customer` | true | The `id` of the previously created customer that will make the payment. Optionally, you can also create the customer at the same time (see the code example). | Once you successfully create a Payment Intent, you will need to use the URL in the `payment_method_information.open_finance.redirect_url` parameter to redirect your user to their financial institution to confirm the payment. After confirming the payment, your user is redirected back to the `callback_url` you provided in the Payment Intent request. ### Single A **single** scheduled payment allows you to set up a one-time transaction for a specific future date. This is ideal for one-off payments where you need to ensure the transaction occurs on a particular day. To create a single scheduled payment, add the following information to your Payment Intent request: ```json Single Scheduled Payment { "amount": "1234.12", "customer": "06dc2f14-1217-4480-9b36-550a944a39d1", "description": "Shoe payment - Single", "statement_descrption": "Super Shoe Store - Brown Sneakers", "allowed_payment_method_types": ["open_finance"], "payment_method_details": { "open_finance": { "schedule": { "single": { "date": "2024-08-01" } }, "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc", "payer_institution": "600f1b4a-1ef9-4f89-b341-1a35f0c32cc0", "callback_url": "https://www.acmecorp.com/checkout/3487321" } }, "confirm": true } ``` | Field | Description | Example | | --- | --- | --- | | `date` | The date when the payment should occur on, in `YYYY-MM-DD` format. The date must be at least 1 day into the future and no more than 720 days into the future. | `2024-08-01` | ### Daily **Daily** scheduled payments enable recurring transactions every day starting from a specified date. This is perfect for frequent, regular payments such as daily subscriptions or repetitive services. To create a daily scheduled payment, add the following information to your Payment Intent request: ```json Daily Recurring Payment { "amount": "1234.12", "customer": "06dc2f14-1217-4480-9b36-550a944a39d1", "description": "Shoe payment - Daily", "statement_descrption": "Super Shoe Store - Brown Sneakers", "allowed_payment_method_types": ["open_finance"], "payment_method_details": { "open_finance": { "schedule": { "daily": { "start_date": "2025-04-09", "occurrences": 2 } }, "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc", "payer_institution": "600f1b4a-1ef9-4f89-b341-1a35f0c32cc0", "callback_url": "https://www.acmecorp.com/checkout/3487321" } }, "confirm": true } ``` | Field | Description | Example | | --- | --- | --- | | `start_date` | The date when the recurring payments should begin, in `YYYY-MM-DD` format. | `2024-08-01` | | `occurrences` | The number of times this recurring payment should repeat. The minimum value is `2` and the maximum value is `60`. | `52` | ### Weekly **Weekly** scheduled payments allow you to set up recurring transactions on a specific day of each week. This is useful for weekly services or recurring obligations that occur on the same weekday. To create a weekly scheduled payment, add the following information to your Payment Intent request: ```json Weekly Recurring Payment { "amount": "1234.12", "customer": "06dc2f14-1217-4480-9b36-550a944a39d1", "description": "Shoe payment - Weekly", "statement_descrption": "Super Shoe Store - Brown Sneakers", "allowed_payment_method_types": ["open_finance"], "payment_method_details": { "open_finance": { "schedule": { "weekly": { "start_date": "2025-04-09", "day_of_week": "MONDAY", "occurrences": 2 } }, "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc", "payer_institution": "600f1b4a-1ef9-4f89-b341-1a35f0c32cc0", "callback_url": "https://www.acmecorp.com/checkout/3487321" } }, "confirm": true } ``` | Field | Description | Example | | --- | --- | --- | | `start_date` | The date when the recurring payments should begin, in `YYYY-MM-DD` format. At present, this date must be the same as the first `day_of_week` you provide. | `2024-08-01` | | `day_of_week` | The day of the week that this payment should be settled on. Can be one of the following: `MONDAY`, `TUESDAY`, `WEDNESDAY`, `THURSDAY`, `FRIDAY`, `SATURDAY`, or` SUNDAY`. | `MONDAY` | | `occurrences` | The number of times this recurring payment should repeat. The minimum value is `2` and the maximum value is `60`. | `52` | ### Monthly **Monthly** scheduled payments are designed for transactions that repeat on the same day each month. This setup is ideal for monthly bills, subscriptions, or any regular monthly payments. To create a monthly scheduled payment, add the following information to your Payment Intent request: ```json Monthly Recurring Payment { "amount": "1234.12", "customer": "06dc2f14-1217-4480-9b36-550a944a39d1", "description": "Shoe payment - Monthly", "statement_descrption": "Super Shoe Store - Brown Sneakers", "allowed_payment_method_types": ["open_finance"], "payment_method_details": { "open_finance": { "schedule": { "monthly": { "start_date": "2025-04-26", "day_of_month": 26, "occurrences": 12 } }, "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc", "payer_institution": "600f1b4a-1ef9-4f89-b341-1a35f0c32cc0", "callback_url": "https://www.acmecorp.com/checkout/3487321" } }, "confirm": true } ``` | Field | Description | Example | | --- | --- | --- | | `start_date` | The date when the recurring payments should begin, in `YYYY-MM-DD` format. At present, this date must be the same as the first `day_of_month` you provide. | `2024-08-01` | | `day_of_month` | The day of the month (between `1` and `31`) that the payment should occur on. **Note**: If you choose a day that does not appear in all months (for example, `31`), then in months that this date does not occur the payment will be made on the next day. For example, as June only has 30 days, the payment will be processed on July 1st (and then again on July 31st). To avoid charging your users twice in the same month, we suggest you choose a day up to the 28th. | `26` | | `occurrences` | The number of times this recurring payment should repeat. The minimum value is `2` and the maximum value is `24`. | `12` | ### Custom **Custom** scheduled payments offer flexibility by allowing you to specify an array of dates for recurring transactions. This option is perfect for irregular schedules or bespoke payment plans that do not fit standard recurrence patterns. To create a custom scheduled payment, add the following information to your Payment Intent request: ```json Custom Recurring Payment { "amount": "1234.12", "customer": "06dc2f14-1217-4480-9b36-550a944a39d1", "description": "Shoe payment - Custom Schedule", "statement_descrption": "Super Shoe Store - Brown Sneakers", "allowed_payment_method_types": ["open_finance"], "payment_method_details": { "open_finance": { "schedule": { "custom": { "dates": ["2024-06-27", "2024-07-27", "2024-08-26", "2024-09-25", "2024-10-25"] } }, "beneficiary_bank_account": "a80d5a9d-20ae-479a-8dd7-ff3443bcbbfc", "payer_institution": "600f1b4a-1ef9-4f89-b341-1a35f0c32cc0", "callback_url": "https://www.acmecorp.com/checkout/3487321" } }, "confirm": true } ``` | Field | Description | Example | | --- | --- | --- | | `dates` | The array of dates when the recurring payments should occur on, in `YYYY-MM-DD` format. The minimum number of dates is `2` and the maximum number of dates is `60`. The dates must be at least 1 day into the future and no more than 720 days into the future. | `["2024-06-27", "2024-07-27"]` | | `description` | A description of the custom recurring payment that will display to your user when they are redirected to their bank to give their consent and accept the payment. **Note**: We highly recommend that this message be in Brazilian Portuguese, and that it clearly explains the purpose as well as recurring nature of the payment. | `Os pagamentos ocorrerão a cada três dias até a data final (09.07.2024)` | ## Payment Intents, Charges, and Transactions For each scheduled payment, Belvo generates a **Charge** object within the Payment Intent response body. Once a Charge is processed successfully, Belvo generates a **Transaction** associated with that Charge. For example, if you create a recurring payment that will occur two times, the `charges` array in the Payment Intent will include **two** Charges. And once the first Charge is processed, Belvo generates an associated Transaction. ## Payment Statuses and Notifications Once you schedule a payment, you will receive webhook updates for the associated Payment Intent, Charges, and Transactions. Below you can see an example of a recurring scheduled payment and the associated statuses each payment will go through. You will receive `STATUS_UPDATE` webhook notifications for each status that is marked with a red dot (🔴). When you receive the `OBJECT_CREATED` Transaction webhook event, this indicates that the given scheduled payment was settled. Once all the scheduled Charges have been completed (including those that fail), the Payment Intent status will be set to `SCHEDULE_FINISHED`. To see whether a Payment Intent has any failed Charges, you can use the List all Charges method, filtering by the `id` of the Payment Intent: ```curl curl --request GET \ --url 'https://api.belvo.com/payments/br/payment-intents/{payment_intent_id}/charges/' \ --header 'accept: application/json' \ ---u SECRET_ID:SECRET_PASSWORD ``` | Field | Description | Example | | --- | --- | --- | | `payment_intent_id` | The `payment-intent.id` that you want to get Charges for. | `65492eeb-344c-49fe-8dab-11da1be67d7a` | ## Cancel a payment ### Cancelling a specific charge To cancel a specific scheduled charge, you just need to make a POST Cancel a scheduled Charge API call: ```curl Cancel Singular Charge curl --request POST \ --header 'accept: application/json' \ -u SECRET_ID:SECRET_PASSWORD \ --url https://api.belvo.com/payments/br/payment-intents/{payment_intent_id}/charges/{charge_id}/cancel/ \ ``` | Field | Description | Example | | --- | --- | --- | | `payment_intent_id` | The scheduled `payment-intent.id` the charge belongs to. | `65492eeb-344c-49fe-8dab-11da1be67d7a` | | `charge_id` | The scheduled `charge.id` you want to cancel. | `414c6387-2d46-45cc-84a8-e1d175aebe53` | The latest you can cancel a scheduled Charge is by 23:59:00 (GMT-3) on the day before the scheduled payment date. If you miss the cutoff time, you will receive and API error from Belvo and the payment will go through. ### Cancelling an entire Payment Intent To cancel a Payment Intent (and all associated scheduled Charges), you just need to make a POST Cancel a Payment ntent API call: ```curl Cancel Entire Payment Intent curl --request POST \ --header 'accept: application/json' \ -u SECRET_ID:SECRET_PASSWORD \ --url https://api.belvo.com/payments/br/payment-intents/{payment_intent_id}/cancel/ \ ``` | Field | Description | Example | | --- | --- | --- | | `id` | The `payment-intent.id` that you want to cancel. | `65492eeb-344c-49fe-8dab-11da1be67d7a` | After you make your cancellation request, Belvo will respond with a `204 - No Content`, and notify you using a webhook that the status of the Payment Intent has been changed to `CANCELED`. The latest you can cancel a scheduled Payment Intent is by 23:59:00 (GMT-3) on the day before the scheduled payment date. If you miss the cutoff time, you will receive and API error from Belvo and the payment will go through.