> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nekt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# BTG Empresas as a data source

> Bring your BTG Pactual Empresas corporate card transactions (including the open invoice), credit card invoices, account balances and statements to Nekt.

BTG Pactual Empresas is BTG Pactual's digital bank account for companies (Conta PJ). This connector brings your corporate cards, every credit card invoice (the open one included) with its transactions, and your checking accounts' daily balance and statement entries to the Catalog, so you can follow card spending before the invoice closes and reconcile invoices and bank entries with your other data.

> [!NOTE]
>
> The connector only reads data. It never creates, changes or pays anything in BTG.

> [!NOTE]
>
> This is the BTG Empresas connector (your company's bank account). It is not the BTG Parceiros connector, which reads BTG's partner reports.

## Before you start

BTG only gives access to account and card data through an **app that your company creates** in BTG's Developer Area, authorized by a person of your company. Nekt cannot create this app for you. You need:

* A BTG Empresas account with the **Advanced plan**: BTG requires it for apps that read real data (production apps).
* A user registered as **developer** by the account holder, to create the app in the [Developer Area](https://developers.empresas.btgpactual.com).
* A user with the **Operator** profile (or higher) in the company's account, to authorize the app. An authorization made by a user with only the developer profile does not read account data.

### 1. Create a production app in BTG

In BTG's Developer Area, click **Criar Aplicativos** with the environment toggle (top right) set to **Produção**, and fill in:

* **Nome**: any name, for example "Nekt".
* **Tipo**: **Confidencial** (only confidential apps can read banking data).
* **Modelo de integração**: **First-party** (the app reads your own company's account).
* **URL de redirecionamento**: an address you control. After the authorization, BTG sends the browser there with a code in the address bar, so it can be any page of your company's site that you can open.
* **Escopos**: `openid`, the **read-only credit card** scope and the **read-only account** scope (balance and statement). BTG's login service publishes them as `brn:btg:empresas:banking:credit-cards.readonly` and `empresas.btgpactual.com/accounts.readonly`, but BTG's pages use other names too, so always copy the exact scope names your app shows in the Developer Area and use those in the next step.

Production apps go through BTG's review, which takes up to 7 business days. When the app is approved, open its **Detalhes** and the **Chaves** tab, and copy the **Client ID** and **Client Secret**.

> [!TIP]
>
> An app used only by Nekt keeps the Nekt sync out of BTG's request limit of your other systems (BTG allows 120 requests per minute per app). If you reuse an app your company already has, make sure it has the scopes above and do a separate authorization for Nekt (next step), so that each system has its own refresh token.

> [!WARNING]
>
> Use **one Nekt source per authorization**, and never the authorization of another system. Each time BTG issues a new access token for an authorization, the previous one stops working, so two consumers of the same authorization keep knocking each other out.

### 2. Authorize the app and get the refresh token

1. In a browser, open the address below, replacing `CLIENT_ID` and `REDIRECT_URI` with your app's values (the redirect address must be exactly the one registered in the app) and, if your app shows different scope names, the scopes after `scope=` with your app's (separated by `%20`):

   ```bash theme={null}
   https://id.btgpactual.com/oauth2/authorize?client_id=CLIENT_ID&response_type=code&redirect_uri=REDIRECT_URI&scope=openid%20brn:btg:empresas:banking:credit-cards.readonly%20empresas.btgpactual.com/accounts.readonly&prompt=login
   ```

2. Log in with a user that has the **Operator** profile (or higher), **select your company** on the consent screen and confirm.

3. BTG opens your redirect address with `?code=...` at the end. Copy the value of `code` and, within a few minutes, exchange it for tokens:

   ```bash theme={null}
   curl -X POST https://id.btgpactual.com/oauth2/token \
     -u "CLIENT_ID:CLIENT_SECRET" \
     -d grant_type=authorization_code \
     -d code=THE_CODE \
     -d redirect_uri=REDIRECT_URI
   ```

4. From the answer, copy the value of `refresh_token`. You will paste it in Nekt. Keep it, like the client secret, as a password.

> [!WARNING]
>
> A BTG refresh token **expires after 10 days without use**. Every run renews it, so a source that runs daily keeps working indefinitely. If the source stays paused or stops running for more than 10 days (for example after three failed runs in a row, which pause it), repeat this step and paste the new refresh token in the source.

## Configuring BTG Empresas as a Source

In the [Sources](https://app.nekt.ai/sources) tab, click on the "Add source" button located on the top right of your screen. Then, select the BTG Empresas option from the list of connectors.

Click **Next** and you'll be prompted to add your access.

### 1. Add account access

The following configurations are available:

* **Company CNPJ**: the CNPJ of the company you selected when authorizing the app, with or without punctuation.

* **Client ID**: the Client ID of your BTG app.

* **Client Secret**: the Client Secret of your BTG app. If you generate a new secret in BTG, update it here.

* **Refresh Token**: the refresh token from the authorization above.

* **Start Date**: the first day to read. Statements are read from this day on, and invoices whose cycle closes on or after it are read with all their transactions. For example, `2026-01-01`.

* **Statement Type** (advanced, optional): (Default: Simple) which statement BTG lists for your checking accounts: **Simple** (money in and out, without investment yields), **With yields**, or **With yields, investments and redemptions**.

* **Statement Lookback Days** (advanced, optional): (Default: 30) each run reads the statements again from this many days before the last day already read, to catch entries BTG posts late with an earlier date, for example after a long holiday. From 0 to 90.

Once you're done, click **Next**.

### 2. Select streams

Choose which data streams you want to sync. For faster extractions, select only the streams that are relevant to your analysis. You can select entire groups of streams or pick specific ones.

> Tip: The stream can be found more easily by typing its name.

Cards, Invoices and Invoice Transactions need the credit card scope. Accounts, Account Balances and Account Statements need the account scope. If your app only has one of them, select only the streams of that scope.

Select the streams and click **Next**.

### 3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.

* **Layer**: choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
* **Folder**: a folder can be created inside the selected layer to group all tables being created from this new data source.
* **Table name**: we suggest a name, but feel free to customize it. You have the option to add a **prefix** to all tables at once and make this process faster!
* **Sync Type**: Invoices, Invoice Transactions, Account Balances and Account Statements are INCREMENTAL, which is the recommended type for them. Cards and Accounts are FULL\_TABLE: they are read in full on every run, so their tables always show the current state. Read more about Sync Types [here](https://docs.nekt.com/get-started/core-concepts/types-of-sync).

> [!WARNING]
>
> BTG only gives the balance **as it is now**. **Account Balances** builds the history itself, keeping one row per account per day (Brasília time); a full sync of this stream, or an [Additional Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync), replaces the table with today's row only. Do not use full syncs on this stream.

Once you are done configuring, click **Next**.

### 4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters.

To define your [Trigger](https://docs.nekt.com/runs/scheduling-and-triggers), consider how often you want data to be extracted from this source. **Once a day** is enough for most uses, and it keeps the refresh token alive. Several runs per day are fine if you want card spending sooner: each run reads the open invoice again.

Optionally, you can define some additional settings:

* Configure Delta Log Retention and determine for how long we should store old states of this table as it gets updated. Read more about this resource [here](https://docs.nekt.com/get-started/core-concepts/resource-control).
* Determine when to execute an [Additional Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync). A full sync reads every invoice since the Start Date with all its transactions and every statement entry since the Start Date again. Avoid it on Account Balances (see above).

Once you are ready, click **Next** to finalize the setup.

### 5. Check your new source

You can view your new source on the [Sources](https://app.nekt.ai/sources) page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.

> [!WARNING]
>
> For you to be able to see it on your [Catalog](https://app.nekt.ai/catalog), you need at least one successful source run.

> [!NOTE]
>
> Each run first checks, with one request per scope, that the authorization can read what the selected streams need. If a scope is missing, the run stops before writing anything and the log names the streams and the scope. If BTG keeps failing or returns an inconsistent list while a stream is being read, the run stops before writing that stream, so its table is never replaced or updated with a partial read.

## Card transactions before the invoice closes

BTG lists the open invoice of the credit card (the current one) together with the closed ones, and returns its transactions in the same way, so **purchases appear in Invoice Transactions before the invoice closes**, on the next run after BTG registers them. The column `is_posted` tells whether BTG already posted the transaction on the invoice.

Transactions of an invoice can still change after it closes (refunds, installments, adjustments, credits posted up to the due date), so every invoice that is not final is read again on every run: the open one, future ones that already hold installments, and closed ones until **15 days after their due date**. Older invoices are read once more after that and then kept as they are.

A purchase that BTG removes from an invoice that is still being read (for example, a cancelled authorization, or one BTG posts again under a new identifier) stays in the table with `is_removed = true` and **every other column empty**, so it does not count twice. Its original values (merchant, amount, date) remain only in the history of your table in the destination, for example the table's previous versions in the Catalog. To avoid false removals, a purchase is marked as removed only when two reads of the invoice in the same run both miss it, and an invoice that suddenly comes back empty while it still shows a total or charges is never taken as removals: the run warns you and reads it again next time. An invoice with no total and no charges left (for example, the only installment of a future invoice was cancelled) has its purchases marked as removed once both reads come back empty. To see only what BTG lists now, filter the removed rows out:

```sql theme={null}
SELECT *
FROM invoice_transactions
WHERE NOT is_removed
```

## Troubleshooting

| What the run log says | What to do |
| :- | :- |
| BTG no longer accepts the refresh token | The refresh token expired (10 days without a run) or the authorization was revoked. Repeat step 2 of "Before you start" and paste the new refresh token. |
| BTG did not accept the Client ID / Client Secret | Copy both again from your app's **Detalhes > Chaves** tab. A regenerated secret replaces the old one. |
| BTG denied access (403) | The authorization lacks a scope, was made by a user without the Operator profile, did not select the company, or is for a CNPJ other than the one in the source. Authorize again with the scopes above, or deselect the streams named in the log. |
| BTG returned no account for this authorization | The company was not selected on BTG's consent screen. Authorize again and select it. |
| BTG returned an empty card list although the company has current credit card invoices | Usually temporary: the run stops and the cards table is kept. If it repeats, check that the authorization has the credit card scope and was made by a user who sees the company's cards. |
| Nekt could not read (or open the storage of) the BTG token saved for this source | A temporary storage error. The run stops without trying an old token; run it again. If it repeats, contact Nekt support. |
| BTG replaced this source's refresh token and Nekt could not save the new one | The data of that run was delivered, but the next run would fail. Repeat step 2 of "Before you start" and paste the new refresh token. |
| BTG returned no transactions for credit card invoices that had transactions before | Usually temporary: nothing is removed and the invoices are read again in the next run. If it repeats, check that the authorization was made by a user who sees every company card. |

# Streams and Fields

## Available streams

The table below lists every stream, its **slug** (the exact identifier to pass when creating the source via API) and a short description.

| Stream | Slug | Description |
| - | - | - |
| Cards | `cards` | Every corporate card of the company, with status, holder and last four digits. |
| Invoices | `invoices` | Every credit card invoice since the Start Date, open and closed, with totals, due dates, payment and status. |
| Invoice Transactions | `invoice_transactions` | The transactions of each invoice, the open one included, with date, merchant, amount, currency, IOF, installment and card. |
| Accounts | `accounts` | The company's BTG checking accounts. |
| Account Balances | `account_balances` | One balance snapshot per account per day. |
| Account Statements | `account_statements` | Every statement entry of each account (money in and out), with description and category. |

Timestamps are in UTC (BTG sends Brasília time, which the connector converts). Dates such as due dates and statement days are kept as BTG gives them. Amounts are decimals. Lists of objects (invoice summary, all amounts and taxes of a transaction) are JSON text. BTG never returns full card numbers: only the last four digits.

> [!NOTE]
>
> The connector was built from BTG's public API documentation. BTG does not document every value in detail (for example all invoice status values, or the meaning of each amount type of an international purchase); the first runs confirm them.

## Fields by stream

> **Cards**
>
> Every corporate card of the company, as BTG lists it now.
>
> Table: `cards` · Primary key: `card_id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `card_id` | String | Unique identifier of the card (a UUID). Card transactions carry a different, numeric card id: join them to this table by last4\_digits. |
> | `last4_digits` | String | Last four digits of the card number (BTG never returns the full number). |
> | `status` | String | Card status as returned by BTG (documented values: CREATED, REQUESTED). |
> | `printed_name` | String | Name printed on the card. |
> | `modality` | String | Card modality: CREDIT or DEBIT. |
> | `variant` | String | Card variant (for example GOLD). |
> | `type` | String | Card type (for example PHYSICAL or VIRTUAL). |
> | `activated_at` | Date | Date the card was activated. |
> | `owner_name` | String | Name of the cardholder. |
> | `owner_document` | String | CPF or CNPJ of the cardholder. |
> | `debit_account_branch` | String | Branch of the checking account linked to the card, when there is one. |
> | `debit_account_number` | String | Number of the checking account linked to the card, when there is one. |
> | `synced_at` | Datetime | When the sync that wrote this row started (UTC). |

> **Invoices**
>
> Every credit card invoice whose cycle closes on or after the Start Date: the open (current) one, the closed ones and future ones that already hold installments, with totals, due dates, payment data and status. Every invoice is updated on every run.
>
> Table: `invoices` · Primary key: `invoice_id` · Sync: Incremental (`synced_at`), every invoice in scope updated on every run
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `invoice_id` | Integer | Unique identifier of the credit card invoice. |
> | `credit_account_id` | Integer | Identifier of the credit account the invoice belongs to. |
> | `month` | Integer | Reference month of the invoice. |
> | `year` | Integer | Reference year of the invoice. |
> | `cycle_status` | String | Status of the invoice cycle as returned by BTG (for example OPEN for the invoice still open). |
> | `is_current` | Boolean | True for the current invoice (the one still receiving purchases). |
> | `is_final` | Boolean | True when the invoice is not current and 15 days have passed since its due date: its transactions are no longer re-read. |
> | `cycle_opening_date` | Date | Date the invoice cycle opened. |
> | `cycle_closing_date` | Date | Date the invoice cycle closes (or closed). |
> | `due_date` | Date | Due date of the invoice. |
> | `real_due_date` | Date | Actual due date (moved to the next business day when needed). |
> | `best_transaction_day` | Date | Best purchase day of the cycle. |
> | `total_balance` | Decimal | Total amount of the invoice. |
> | `remaining_balance` | Decimal | Amount still to be paid. |
> | `paid_balance` | Decimal | Amount already paid. |
> | `previous_balance` | Decimal | Balance of the previous invoice. |
> | `minimum_payment` | Decimal | Minimum payment of the invoice. |
> | `partial_payment` | Decimal | Partial payment amount (from the invoice detail). |
> | `debits` | Decimal | Total debits of the invoice. |
> | `credits` | Decimal | Total credits of the invoice (refunds, payments credited). |
> | `chargeback_balance` | Decimal | Chargeback amount of the invoice (from the invoice detail). |
> | `can_pay` | Boolean | Whether the invoice can be paid. |
> | `payment_date` | Date | Date the invoice was paid (from the invoice detail). |
> | `can_download_invoice` | Boolean | Whether the invoice PDF can be downloaded (from the invoice detail). |
> | `can_download_excel_invoice` | Boolean | Whether the invoice spreadsheet can be downloaded (from the invoice detail). |
> | `available_payment_methods` | Array of strings | Payment methods available for the invoice, such as BANKSLIP (from the invoice detail). |
> | `installment_conditions` | String (JSON) | Installment payment conditions of the invoice (JSON object, from the invoice detail). |
> | `summary` | String (JSON) | Invoice summary by section and category (JSON array, from the invoice detail). |
> | `detail_read` | Boolean | Whether the invoice detail was read in this sync; when false the detail columns are empty. |
> | `synced_at` | Datetime | When the sync that wrote this row started (UTC); incremental replication key. |

> **Invoice Transactions**
>
> The transactions of each invoice, including the invoice that is still open: purchases, installments, refunds and charges, with merchant, amounts, currency, IOF and the card used. Invoices that are not final are read again on every run; a transaction BTG no longer lists comes back with is\_removed = true.
>
> Table: `invoice_transactions` · Primary key: `invoice_id`, `id` · Sync: Incremental (`synced_at`), invoices that are not final read again on every run
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `invoice_id` | Integer | Invoice the transaction belongs to. |
> | `id` | Integer | Identifier of the card transaction. |
> | `is_removed` | Boolean | True when BTG no longer lists this transaction on the invoice (for example an authorization dropped before posting); the other columns of a removed row are empty. |
> | `event_date` | Datetime | Date and time of the purchase or event (UTC; BTG sends Brasília time). |
> | `created_at` | Datetime | Date and time the transaction was created at BTG (UTC; BTG sends Brasília time). |
> | `installment` | Integer | Installment number of this transaction (1 for single payments). |
> | `number_of_installments` | Integer | Total number of installments of the purchase. |
> | `soft_descriptor` | String | Short description of the transaction as shown on the invoice. |
> | `processing_code` | String | Processing code of the transaction. |
> | `processing_description` | String | Processing description of the transaction. |
> | `customer_id` | Integer | Identifier of the customer associated with the transaction. |
> | `user_category` | String | Category assigned by the user. |
> | `transaction_type_id` | Integer | Identifier of the transaction type. |
> | `transaction_type_description` | String | Description of the transaction type (for example 'Compra à vista'; refunds and reversals show here). |
> | `is_credit` | Boolean | True for credits on the invoice (refunds, reversals, payments), false for purchases and charges. |
> | `is_posted` | Boolean | Whether the transaction was already posted (lançada) on the invoice. |
> | `principal_amount` | Decimal | Amount of type PRINCIPAL (the transaction amount). |
> | `principal_currency` | String | Currency of the PRINCIPAL amount. |
> | `settlement_amount` | Decimal | Amount of type SETTLEMENT, when BTG sends it. |
> | `settlement_currency` | String | Currency of the SETTLEMENT amount. |
> | `local_amount` | Decimal | Amount of type LOCAL, when BTG sends it. |
> | `local_currency` | String | Currency of the LOCAL amount. |
> | `amounts` | String (JSON) | Every amount of the transaction with type, currency, value and exchange rate (JSON array, as returned by BTG). |
> | `iof_amount` | Decimal | IOF charged on the transaction (sum of its IOF taxes); empty when BTG lists none. |
> | `interest_amount` | Decimal | Interest charged on the transaction (sum of its INTEREST taxes); empty when BTG lists none. |
> | `taxes` | String (JSON) | Every tax of the transaction (JSON array of type and value, as returned by BTG). |
> | `merchant_name` | String | Name of the merchant. |
> | `merchant_type` | String | Type of the merchant (for example NETWORK). |
> | `merchant_city` | String | City of the merchant. |
> | `merchant_state` | String | Location of the merchant's city, as returned by BTG. |
> | `merchant_category_code` | String | Merchant category code (MCC). |
> | `merchant_category_description` | String | Description of the merchant category. |
> | `merchant_category_group` | String | Group of the merchant category (for example Alimentação). |
> | `merchant_network_group` | String | Network group of the merchant category (for example FOOD). |
> | `card_id` | Integer | Numeric identifier of the card used (not the cards table's card\_id; join by card\_last4\_digits). |
> | `card_name` | String | Name printed on the card used. |
> | `card_last4_digits` | String | Last four digits of the card used. |
> | `card_type` | String | Type of the card used (for example PHYSICAL or VIRTUAL). |
> | `card_owner_name` | String | Name of the cardholder. |
> | `card_modality` | String | Modality of the card used (for example CREDIT). |
> | `is_international` | Boolean | Whether the transaction is international. |
> | `is_dcc` | Boolean | Whether the transaction used Dynamic Currency Conversion. |
> | `synced_at` | Datetime | When the sync that last read this transaction's invoice started (UTC); incremental replication key. |

> **Accounts**
>
> The company's BTG checking accounts that the authorization reaches.
>
> Table: `accounts` · Primary key: `account_id` · Sync: Full table
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `account_id` | String | BTG account identifier (CNPJ-bank-branch-number), used by the balance and statement requests. |
> | `tax_id` | String | CNPJ of the account holder. |
> | `bank_code` | Integer | Bank code (208 for BTG Pactual). |
> | `branch_code` | String | Branch (agência) of the account. |
> | `number` | String | Account number. |
> | `synced_at` | Datetime | When the sync that wrote this row started (UTC). |

> **Account Balances**
>
> One balance snapshot per account per day (Brasília time); the last run of the day wins.
>
> Table: `account_balances` · Primary key: `account_id`, `snapshot_date` · Sync: Incremental (`synced_at`), one row per account per day
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `account_id` | String | BTG account identifier. |
> | `snapshot_date` | Date | Day (Brasília time) of the snapshot; one row per account and day. |
> | `available_amount` | Decimal | Available balance at the time of the sync. |
> | `available_currency` | String | Currency of the available balance. |
> | `blocked_amount` | Decimal | Blocked balance at the time of the sync. |
> | `blocked_currency` | String | Currency of the blocked balance. |
> | `blocked_date` | Datetime | Date of the block, as returned by BTG (UTC). |
> | `synced_at` | Datetime | When the sync that read the balance started (UTC); incremental replication key. |

> **Account Statements**
>
> Every statement entry (money in and out) of each checking account, with description and category.
>
> Table: `account_statements` · Primary key: `account_id`, `id` · Sync: Incremental (`movement_date`), one bookmark per account
>
> | Field | Type | Description |
> | :- | :- | :- |
> | `account_id` | String | BTG account identifier. |
> | `id` | Integer | Identifier of the statement entry. |
> | `movement_date` | Date | Business day of the entry (Brasília time); incremental replication key. |
> | `date_hour` | Datetime | Date and time of the entry (UTC). |
> | `type` | String | Direction of the entry: credit (money in) or debit (money out). |
> | `category_name` | String | Category code of the entry (for example PIX, OTHERS). |
> | `category_description` | String | Category description of the entry. |
> | `description` | String | Description of the entry (for example 'Pix realizado'). |
> | `description_details` | String | Additional description (counterparty, internal description given when the payment was created). |
> | `amount` | Decimal | Amount of the entry as returned by BTG (the direction is in 'type'). |
> | `tx_id` | String | Transaction identifier (txId), when applicable. |
> | `end_to_end_id` | String | Pix end-to-end identifier, for Pix entries. |
> | `return_info` | String | Return information, for returned entries. |
> | `origin_id` | String | Identifier of the operation that originated the entry. |
> | `barcode` | String | Boleto barcode, for boleto credits. |
> | `our_number` | String | Boleto 'nosso número', for boleto credits. |
> | `day_balance` | Decimal | Account balance reported by BTG for the entry's day. |
> | `statement_type` | String | Statement listing the entry was read with (simple, yields or withdraw-applications). |
> | `synced_at` | Datetime | When the sync that wrote this row started (UTC). |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.