# Creating a preauthorization

In this section, you will learn how to create a preauthorization to do payments without user interaction.

## Create a payment recipient

First, you need to create **Payment Recipients**. Those will be the allowed destinations to send transfers. All of recipients must belong to the same owner.

```shell
curl --location 'https://api.pluggy.ai/payments/recipients' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: ••••••' \
--data '{
  "account": {
    "type": "CHECKING_ACCOUNT",
    "number": "1111111",
    "branch": "0001"
  },
  "paymentInstitutionId": "abfd2a88-bc7b-407f-9fcc-395548ee6840",
  "name": "John Doe",
  "taxNumber": "11111111111"
}'
```

Check the [API docs](/reference/payment-recipient/payment-recipient-create) to know how to use this endpoint. To know the `paymentInstitutionId`, you need to use this [endpoint](/reference/payment-recipient/payment-recipients-institution-list).

This will return the following response:

```json
{
  "type": "BANK_ACCOUNT",
  "id": "ded2e966-bd40-4e82-b467-d32fe4b4f40e",
  "name": "John Doe",
  "taxNumber": "11111111111",
  "isDefault": false,
  "paymentInstitution": {
    "id": "abfd2a88-bc7b-407f-9fcc-395548ee6840",
    "name": "Banco XP S.A.",
    "tradeName": "BCO XP S.A.",
    "ispb": "33264668",
    "compe": "348",
    "createdAt": "2023-12-08T17:52:21.001Z",
    "updatedAt": "2023-12-08T17:52:21.001Z"
  },
  "account": {
    "type": "CHECKING_ACCOUNT",
    "number": "1111111",
    "branch": "0001"
  },
  "pixKey": null,
  "createdAt": "2024-08-01T16:32:29.276Z",
  "updatedAt": "2024-08-01T16:32:29.276Z"
}
```

## Create the Smart Transfer Preauthorization

Now, you are ready to create a smart transfer preauthorization. To do that, you need to do the following request:

```shell
curl --location 'https://api.pluggy.ai/smart-transfers/preauthorizations' \
--header 'Content-Type: application/json' \
--header 'X-API-KEY: ••••••' \
--data '{
  "connectorId": 612,
  "parameters": {
    "cpf": "11111111111"
  },
  "recipientIds": [
    "ded2e966-bd40-4e82-b467-d32fe4b4f40e"
  ],
  "callbackUrls": {
    "success": "https://my-success-page.com",
    "error": "https://my-error-page.com"
  },
  "configuration": {
    "transactionLimit": 100
  },
  "linkedJourney": true
}'
```

- The `connectorId` will be the one associated with the institution of your debtor account (for example, if you want to create the preauthorization in Nubank, you need to send the id `612`).

- You can configure the transaction limits sending the `configuration` field (see [Configuring transaction limits section](#configuring-transaction-limits)).

- **linkedJourney** (optional, default false): also ask the user, in the same approval at the bank, for permission to read the source account balance. See [Source account balance](#source-account-balance).

  For more details about this endpoint, check our [API docs](/reference/smart-transfer/smart-transfer-preauthorization-create).

<Callout variant="warning" title="Important">
For PF accounts you can only configure one recipient per authorization. Only PJ accounts can configure multiple recipients for the same authorization.
</Callout>

This will return the following response:

```json
{
  "id": "7e3e1dbb-8009-4966-9254-1eaab05ad18b",
  "status": "CREATED",
  "consentUrl": "https://this-is-the-consent-url.com",
  "clientPreauthorizationId": null,
  "callbackUrls": null,
  "recipients": [
    {
      "type": "BANK_ACCOUNT",
      "id": "ded2e966-bd40-4e82-b467-d32fe4b4f40e",
      "name": "John Doe",
      "taxNumber": "11111111111",
      "isDefault": false,
      "paymentInstitution": {
        "id": "abfd2a88-bc7b-407f-9fcc-395548ee6840",
        "name": "Banco XP S.A.",
        "tradeName": "BCO XP S.A.",
        "ispb": "33264668",
        "compe": "348",
        "createdAt": "2023-12-08T17:52:21.001Z",
        "updatedAt": "2023-12-08T17:52:21.001Z"
      },
      "account": {
        "type": "CHECKING_ACCOUNT",
        "number": "1111111",
        "branch": "0001"
      },
      "pixKey": null,
      "createdAt": "2024-07-31T15:56:03.938Z",
      "updatedAt": "2024-07-31T15:56:23.123Z"
    }
  ],
  "connector": {
    "id": 612,
    "name": "Nubank",
    "primaryColor": "8a0fbe",
    "institutionUrl": "https://nuapp.nubank.com.br/open-banking/logo.svg",
    "country": "BR",
    "type": "PERSONAL_BANK",
    "credentials": [
      {
        "validation": "^\\d{3}\\.?\\d{3}\\.?\\d{3}-?\\d{2}$",
        "validationMessage": "CPF deve ter 11 numeros.",
        "label": "CPF",
        "name": "cpf",
        "type": "number",
        "placeholder": "",
        "optional": false
      }
    ],
    "imageUrl": "https://cdn.pluggy.ai/assets/connector-icons/212.svg",
    "hasMFA": false,
    "oauth": true,
    "health": {
      "status": "ONLINE",
      "stage": null
    },
    "products": [
      "ACCOUNTS",
      "TRANSACTIONS",
      "IDENTITY",
      "CREDIT_CARDS",
      "PAYMENT_DATA",
      "LOANS",
      "INVESTMENTS"
    ],
    "createdAt": "2023-09-01T18:05:09.145Z",
    "isSandbox": false,
    "isOpenFinance": true,
    "updatedAt": "2024-08-01T16:33:57.978Z",
    "supportsPaymentInitiation": true,
    "supportsScheduledPayments": true,
    "supportsSmartTransfers": true
  },
  "dataConsent": {
    "status": "AWAITING_AUTHORISATION",
    "rejectionReason": null,
    "updatedAt": "2026-10-07T18:43:08.390Z"
  },
  "createdAt": "2024-08-01T16:39:27.946Z",
  "updatedAt": "2024-08-01T16:39:32.448Z"
}
```

After the preauthorization is created, you need to redirect your user to the `consentUrl` returned in the response. There, the user needs to approve the preauthorization in their payment institution. After the consent is given, the user will be redirected to the `success` callback url if everything is ok, or to the `error` callback url if the consent was rejected or if an error happens in the process.

Note: if you don't define a set of `callbackUrls`, the user will be redirected to a Pluggy's default page.

Now, if you check the preauthorization status using [this endpoint](/reference/smart-transfer/smart-transfer-preauthorization-retrieve), you will see it with one of the following statuses:

- **COMPLETED**: The preauthorization was completed and you are ready to create payments.
- **REJECTED**: The user rejected the preauthorization in the institution consent flow.
- **ERROR**: There was an error in the institution consent flow.

In the [next section](/docs/smart-transfers/creating-payment), you will see how to create a payment without user interaction.

## Configuring transaction limits

You can configure the transaction limits sending the `configuration` object.

| Field | Type | Optional | Description |
|-------|------|----------|-------------|
| totalAllowedAmount | number | true | Maximum amount to be reached by the sum of all transactions that use the consent authorized by the customer. |
| transactionLimit | number | true | Maximum amount for each payment transaction associated with this consent. |
| periodicLimits | object | true | Transactional limits per period as determined by the paying user. |

In the `periodicLimits` object, you can configure the limits per period. The available periods are `day`, `week`, `month` and `year`, and for each one you can configure:

| Field | Type | Optional | Description |
|-------|------|----------|-------------|
| quantityLimit | number | true | Maximum number of transactions allowed to occur in the period. |
| transactionLimit | number | true | Maximum amount to be transacted in the period. |

Example:

```json
{
  "configuration": {
    "totalAllowedAmount": 100.5,
    "transactionLimit": 10,
    "periodicLimits": {
      "day": {
        "quantityLimit": 2,
        "transactionLimit": 5
      },
      "week": {
        // week limits
      },
      "month": {
        // month limits
      },
      "year": {
        // year limits
      }
    }
  }
}
```

In the case that some limit is reached, you will receive an appropriate error from the API.

## Source account balance

Smart Transfers are paid from the user's account without a new approval, so a transfer can be rejected for insufficient balance. Create the preauthorization with `linkedJourney: true` to also ask the user, in the same approval at the bank, for permission to read the source account balance. Nothing else changes in the redirect, the return or the transfers.

### Permission status

The preauthorization carries a `dataConsent` object while the permission exists. It is `null` when `linkedJourney` was not requested, and it can also be `null` when the balance permission is not available for that institution or environment. In that case the preauthorization is created normally, without the permission.

| `status` | Meaning |
|---|---|
| `AWAITING_AUTHORISATION` | The user has not approved yet. |
| `AUTHORISED` | The balance can be read. |
| `REJECTED` | Rejected, revoked, cancelled or expired. It does not come back; `rejectionReason` says why. |

The permission ends with the preauthorization. If the user revokes either one from their bank, the balance endpoint answers `403`, and the stored status can still read `AUTHORISED` until the institution reports the change.

`dataConsent` is refreshed from the institution when you retrieve the preauthorization by id. The list returns the last known status. `updatedAt` is when Pluggy last saw the status change.

### Read the balance

`GET /smart-transfers/preauthorizations/{id}/balance` reads the source account balance in real time from the institution. Amounts are in BRL.

```json
{
  "balance": 5.48,
  "overdraft": {
    "contracted": 1000,
    "used": 0,
    "available": 1000
  }
}
```

`overdraft` is the account's overdraft limit: how much was contracted, how much is in use and how much is still available. It is `null` when the institution does not share it.

| Status | `codeDescription` | Meaning |
|---|---|---|
| `200` | | Balance read. |
| `400` | `SMART_TRANSFER_DATA_CONSENT_NOT_REQUESTED` | The preauthorization was created without `linkedJourney`. |
| `403` | `SMART_TRANSFER_DATA_CONSENT_NOT_AVAILABLE` | The permission is pending, rejected or revoked. |
| `429` | `BALANCE_OPEN_FINANCE_RATE_LIMIT` | The rate limit at the institution is reached, for example the account's monthly balance quota. |

<Callout variant="warning" title="Every call counts toward the institution's quota">
Each call reads the balance from the institution, with no cache. Open Finance limits balance reads per account per month (see [Operational Rate Limits](/docs/open-finance/rate-limits)). Read the balance right before a transfer, not on a schedule.
</Callout>

### Cancel only the permission

`DELETE /smart-transfers/preauthorizations/{id}/data-consent` cancels the balance permission and returns the preauthorization with `dataConsent.status` set to `REJECTED`. The preauthorization stays active and its transfers keep working. A permission cannot be added to an existing preauthorization: create a new one with `linkedJourney`.

| Status | `codeDescription` | Meaning |
|---|---|---|
| `200` | | Permission cancelled, or it had already ended. |
| `400` | `SMART_TRANSFER_DATA_CONSENT_NOT_REQUESTED` | The preauthorization was created without `linkedJourney`. |
| `403` | `SMART_TRANSFER_DATA_CONSENT_NOT_AVAILABLE` | The institution did not accept the cancellation, for example because the user has not approved the permission yet. |
| `429` | `BALANCE_OPEN_FINANCE_RATE_LIMIT` | The rate limit at the institution is reached. |

Cancelling a permission that already ended (rejected, revoked, or its preauthorization revoked or rejected) answers `200` with `status: REJECTED`, so retrying is safe.