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

# Business policies and approvals

> How your organization's policies decide whether a Pix or boleto payment is paid right away, needs approval, or is refused

An organization's admins write **business policies** — rules such as "Pix payments above R\$ 1,000 need the finance team's approval" or "no payments from the Marketing wallet on weekends". Every Pix and boleto payment made from the organization's wallets is checked against them, and the matching policy decides what happens to it.

This guide shows how to read that decision and act on it: create the payment, set its details, then either **confirm** it straight away or **send it for approval**.

> [!NOTE]
>
> The steps below use a Pix payment. Boleto payments follow the same policies and the same create → set details → send for approval or confirm flow, through their own endpoints and with their own error codes — see [Boleto payments](#boleto-payments).
>
> Transfer requests between wallets are checked against the same policies and go through the same send for approval or confirm steps, with their own endpoints and error codes. The main differences: their amount and balance category are fixed when they are created — to change them, cancel the request and create a new one — and only organization admins can cancel them.

## What a policy decides

The organization's policies are evaluated in their `order`, and the **first one whose conditions match** the payment decides. Conditions read the payment as it stands: its amount, the balance category it is charged to, the recipient, the paying wallet, who created it, its custom fields, and how many days are left to its due date.

The decision is the policy's `actions.autoAction`:

| `autoAction` | Meaning | What you do |
| - | - | - |
| `APPROVE` | The payment is allowed. Also the answer when **no policy matches**. | [Confirm it](#step-3a-confirm-the-payment) — the money moves. |
| `NONE` | The payment needs approval from the people or groups in `actions.approvals`. | [Send it for approval](#step-3b-send-the-payment-for-approval) — it is paid once approved. |
| `DENY` | The payment is refused. | Nothing — it can't be paid, except by an [organization admin](#organization-admins). [Cancel it](https://developers.portao3.com.br/api-reference/banking/pix-payments/cancel-a-pix-payment.md) to close it. |

A policy can also **top up the wallet** before paying (`actions.moveBalance`): the payment's amount is first moved into the paying wallet from another one, then paid. That happens on its own when a payment the policy approves is confirmed, and when an approval request is approved — you don't do anything extra. An organization admin who confirms a payment the policy would send for approval, or refuse, gets no top-up. A payment for a later day (`scheduledAt`) that you confirm directly is not topped up — make sure the wallet has the money on that day; one that goes through an approval is topped up when it is approved.

Admins manage the policies in the Portão 3 app or through the Rule Engine API's [business policies](https://developers.portao3.com.br/api-reference/ruleengine/business-policies/realms-organizations-business-policies.md) endpoints.

## The flow

```mermaid theme={null}
flowchart TD
  A["POST .../pix<br/>create the payment"] --> B{"amount and<br/>category set?"}
  B -- no --> C["PUT .../pix/{pixId}<br/>set the details"]
  B -- yes --> D{"policy.actions.autoAction"}
  C --> D
  D -- APPROVE --> E["POST .../pix/{pixId}/confirm<br/>the money moves"]
  D -- NONE --> F["POST .../pix/{pixId}/request<br/>PENDING_APPROVAL"]
  D -- DENY --> G["refused —<br/>cancel it"]
  F -- approved --> H["confirmed automatically<br/>CONFIRMED, then PAID"]
  F -- denied --> I["CANCELLED"]
  F -- deadline passed --> J["EXPIRED"]
```

Every step answers with the payment, so you always know its `status`.

## Step 1: Create the payment

[Create the Pix payment](https://developers.portao3.com.br/api-reference/banking/pix-payments/create-a-pix-payment.md) with the recipient — a Pix key, a Pix Copia e Cola / QR code, or bank details. Nothing is paid yet: the payment starts as `REQUESTED`.

```bash theme={null}
curl -X POST \
  'https://api.banking.v2.portao3.com.br/realms/{realmId}/organizations/{organizationId}/accounts/{accountId}/wallets/{walletId}/pix' \
  -H 'Authorization: Bearer <accessToken>' \
  -H 'x-environment: LIVE' \
  -H 'Content-Type: application/json' \
  -d '{
    "initiationType": "DICT",
    "dict": "CNPJ",
    "key": "12345678000195",
    "amount": 123000,
    "category": "FLEX_INTERNATIONAL",
    "description": "Folders da campanha de novembro"
  }'
```

The answer brings the payment and `policy` — what the policies say about it **as it stands**:

```json theme={null}
{
  "_id": "6726a4f1b4d3e80012c9a3f1",
  "status": "REQUESTED",
  "txnUpdatedAmount": 123000,
  "creditParty": { "name": "Gráfica Aurora Ltda", "key": "12345678000195" },
  "pendingConfirmation": { "amount": 123000, "category": "FLEX_INTERNATIONAL", "description": "Folders da campanha de novembro" },
  "policy": {
    "id": "3f2e1d0c-9b8a-4c7d-8e6f-5a4b3c2d1e0f",
    "name": "Pagamentos acima de R$ 1.000",
    "actions": {
      "autoAction": "NONE",
      "hierarchy": false,
      "approvals": [{ "type": "USER", "id": "0b6f2c1e-8d4a-4f3b-9a7e-5c2d1e0f9a8b", "name": "Rafael Lima" }]
    }
  }
}
```

Use `_id` as `{pixId}` in the next steps.

## Step 2: Set the details and read the verdict

`pendingConfirmation` holds **what will be paid** — the amount, the balance category charged and a description. Sending for approval and confirming take no details of their own: they use these.

When you sent `amount` and `category` at creation (as above), they are already set and `policy` already reflects them — go to step 3. Otherwise — typically a QR code, whose amount you only know after reading it, or a create without `category` — [set the details](https://developers.portao3.com.br/api-reference/banking/pix-payments/set-a-pix-payments-details.md):

```bash theme={null}
curl -X PUT \
  'https://api.banking.v2.portao3.com.br/realms/{realmId}/organizations/{organizationId}/accounts/{accountId}/wallets/{walletId}/pix/{pixId}' \
  -H 'Authorization: Bearer <accessToken>' \
  -H 'x-environment: LIVE' \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": 123000,
    "category": "FLEX_INTERNATIONAL",
    "customFields": { "cost-center": "CC-1020" }
  }'
```

The answer brings the updated payment and a fresh `policy`. **Read `policy.actions.autoAction` from the latest answer** to choose step 3a, 3b or nothing (`DENY`). You can call `PUT` as many times as you need while the payment is `REQUESTED`.

> [!TIP]
>
> Unless the QR code has an open amount (`txnAllowAmountChange: true`), `amount` must be the payment's `txnUpdatedAmount` (a `COBV` charge scheduled for its due date may also pay its `txnOriginalAmount`). Fill in every required transaction custom field here too — confirming and sending for approval refuse a payment that misses one.

## Step 3a: Confirm the payment

When the verdict is `APPROVE`, [confirm the payment](https://developers.portao3.com.br/api-reference/banking/pix-payments/confirm-a-pix-payment.md). Send no body:

```bash theme={null}
curl -X POST \
  'https://api.banking.v2.portao3.com.br/realms/{realmId}/organizations/{organizationId}/accounts/{accountId}/wallets/{walletId}/pix/{pixId}/confirm' \
  -H 'Authorization: Bearer <accessToken>' \
  -H 'x-environment: LIVE'
```

The policies are evaluated once more, with the stored details. If they still approve, the money moves: the answer is **200** with the payment `CONFIRMED` — it becomes `PAID` when the Pix network settles it. If the payment is for a later day (`scheduledAt`), the answer is **201** with the schedule instead, and the payment becomes `SCHEDULED`.

If a policy now requires approval, the confirmation is refused with `403 PIX_REQUIRES_APPROVAL` — send the payment for approval instead. If a policy refuses it, you get `403 PIX_POLICY_DENIED`.

## Step 3b: Send the payment for approval

When the verdict is `NONE`, [send the payment for approval](https://developers.portao3.com.br/api-reference/banking/pix-payments/send-a-pix-payment-for-approval.md). Send no body:

```bash theme={null}
curl -X POST \
  'https://api.banking.v2.portao3.com.br/realms/{realmId}/organizations/{organizationId}/accounts/{accountId}/wallets/{walletId}/pix/{pixId}/request' \
  -H 'Authorization: Bearer <accessToken>' \
  -H 'x-environment: LIVE'
```

The payment becomes `PENDING_APPROVAL`, and an **approval request** is opened for the approvers the policy names. The answer brings it in `policyRequest`:

```json theme={null}
{
  "_id": "6726a4f1b4d3e80012c9a3f1",
  "status": "PENDING_APPROVAL",
  "policyRequestId": "4d2c1b0a-9f8e-4d7c-8b6a-5f4e3d2c1b0a",
  "approvalExpiresAt": "2026-11-03T00:00:00.000Z",
  "policyRequest": {
    "id": "4d2c1b0a-9f8e-4d7c-8b6a-5f4e3d2c1b0a",
    "status": "REQUESTED",
    "approvalHierarchy": false,
    "approvals": [
      { "type": "USER", "id": "0b6f2c1e-8d4a-4f3b-9a7e-5c2d1e0f9a8b", "name": "Rafael Lima", "status": "REQUESTED", "users": [] }
    ]
  }
}
```

From here:

* **The details are frozen.** The approvers approve exactly the amount, category and description the payment had when it was sent. To change them, [cancel the payment](https://developers.portao3.com.br/api-reference/banking/pix-payments/cancel-a-pix-payment.md) — its approval request is cancelled too — and create a new one.
* **The approvers decide.** They are notified in the Portão 3 app and approve or deny there, or through the Rule Engine API — [approve](https://developers.portao3.com.br/api-reference/ruleengine/policy-requests/realms-organizations-policy-requests-approve.md) or [deny](https://developers.portao3.com.br/api-reference/ruleengine/policy-requests/realms-organizations-policy-requests-deny.md) the approval request whose `id` is the payment's `policyRequestId`. With `approvalHierarchy: true` they decide one after the other, in order. Organization admins can decide any request on their own: [force-approve](https://developers.portao3.com.br/api-reference/ruleengine/policy-requests/realms-organizations-policy-requests-force-approve.md) or [force-deny](https://developers.portao3.com.br/api-reference/ruleengine/policy-requests/realms-organizations-policy-requests-force-deny.md).
* **Approved → paid.** Once every approval is given, Portão 3 confirms the payment for you, with the approved details — no call from you. It becomes `CONFIRMED`, then `PAID` (or `SCHEDULED`, for a later day). If the payment is refused at that point — for example, for insufficient funds — it becomes `FAILED`, with the reason in `failReason`.
* **Approved, but not carried out.** If the policy's top-up of the wallet can't be done after the approval, the payment is not sent. A few problems found before any money moves are retried automatically (the approval request's `executionStatus` goes back to `WAITING`). Any other failure — a timeout or an error from the bank during the top-up included — ends the approval request with `executionStatus: FAILED` and the reason in `executionFailReason`, and the payment stays `PENDING_APPROVAL` until its deadline, then shows as `EXPIRED`. The top-up may have gone through: check the wallets' balances before you cancel the payment and create a new one, and contact support if the money moved.
* **Denied → cancelled.** The payment becomes `CANCELLED`.
* **Deadline passed → expired.** The deadline is `approvalExpiresAt`: 21:00 (São Paulo time) of the day the payment is for, and at least one hour after it was sent. A payment still waiting then becomes `EXPIRED`.

While it waits, the payment can't be confirmed by hand — not even by an organization admin (`403 PIX_PENDING_APPROVAL`): the approval request is the record of the decision.

To follow the outcome, [read the payment](https://developers.portao3.com.br/api-reference/banking/pix-payments/get-a-pix-payment.md) until its `status` leaves `PENDING_APPROVAL`, [read the approval request](https://developers.portao3.com.br/api-reference/ruleengine/policy-requests/realms-organizations-policy-requests-2.md) to see who decided what, or subscribe to the `PIX_OUT` [webhook](https://developers.portao3.com.br/guides/webhooks.md), sent when the payment goes out.

> [!WARNING]
>
> Only send a payment for approval when the verdict is `NONE`. With `APPROVE` the request is refused with `403 PIX_APPROVAL_NOT_REQUIRED` — confirm it instead — and with `DENY`, with `403 PIX_POLICY_DENIED`.

## Organization admins

An organization admin can confirm a payment **whatever the policies decide**: their confirmation skips the approval and still returns the verdict in `policy`, for the record. API clients act as admins of their organizations, so this applies to them too. The only exception is a payment already waiting for approval, which only its approval request can resolve — an admin settles it with force-approve or force-deny.

## When the policies can't be evaluated

If the policies can't be evaluated at that moment:

* creating the payment and setting its details still succeed, with `policy` set to `{ "error": "POLICY_EVALUATION_UNAVAILABLE" }`;
* sending for approval and confirming answer `503 POLICY_EVALUATION_UNAVAILABLE` and change nothing — retry shortly. An organization admin's confirmation goes ahead, with `policy: null`.

## Errors of the flow

| Status | `code` | When | What to do |
| - | - | - | - |
| `403` | `PIX_REQUIRES_APPROVAL` | You confirmed a payment a policy sends for approval. | Send it for approval. |
| `403` | `PIX_POLICY_DENIED` | A policy refuses the payment. | It can't be paid; cancel it. |
| `403` | `PIX_APPROVAL_NOT_REQUIRED` | You sent for approval a payment the policies approve. | Confirm it. |
| `403` | `PIX_PENDING_APPROVAL` | You confirmed a payment that is waiting for approval. | Wait for the approvers. |
| `409` | `PIX_NOT_REQUESTABLE` | You set the details of, or sent for approval, a payment that is no longer `REQUESTED`. | Read the payment; create a new one if needed. |
| `409` | `PIX_STATUS_NOT_REQUESTED` | You confirmed or cancelled a payment that was already confirmed, cancelled or failed. | Read the payment. |
| `409` | `PIX_EXPIRED` | The approval deadline passed; the payment is now `EXPIRED`. | Create a new payment. |
| `422` | `PAYMENT_PARAMETERS_MISSING` | The amount or the balance category isn't set yet. | Set the details with `PUT`. |
| `422` | `CUSTOM_FIELD_IS_REQUIRED` | A required transaction custom field is empty. | Fill it in with `PUT`. |
| `503` | `POLICY_EVALUATION_UNAVAILABLE` | The policies couldn't be evaluated. | Retry shortly. |

## Boleto payments

A [boleto payment](https://developers.portao3.com.br/guides/pay-boleto.md) goes through the same steps, on its own endpoints. Use the payment's `_id` as `{boletoId}`:

| Step | Pix | Boleto |
| - | - | - |
| Create the payment | [`POST .../pix`](https://developers.portao3.com.br/api-reference/banking/pix-payments/create-a-pix-payment) | [`POST .../boleto`](https://developers.portao3.com.br/api-reference/banking/boleto-payments/create-a-boleto-payment) |
| Set the details | [`PUT .../pix/{pixId}`](https://developers.portao3.com.br/api-reference/banking/pix-payments/set-a-pix-payments-details) | [`PUT .../boleto/{boletoId}`](https://developers.portao3.com.br/api-reference/banking/boleto-payments/set-a-boleto-payments-details) |
| Confirm | [`POST .../pix/{pixId}/confirm`](https://developers.portao3.com.br/api-reference/banking/pix-payments/confirm-a-pix-payment) | [`POST .../boleto/{boletoId}/confirm`](https://developers.portao3.com.br/api-reference/banking/boleto-payments/confirm-a-boleto-payment) |
| Send for approval | [`POST .../pix/{pixId}/request`](https://developers.portao3.com.br/api-reference/banking/pix-payments/send-a-pix-payment-for-approval) | [`POST .../boleto/{boletoId}/request`](https://developers.portao3.com.br/api-reference/banking/boleto-payments/send-a-boleto-payment-for-approval) |
| Cancel | [`POST .../pix/{pixId}/cancel`](https://developers.portao3.com.br/api-reference/banking/pix-payments/cancel-a-pix-payment) | [`POST .../boleto/{boletoId}/cancel`](https://developers.portao3.com.br/api-reference/banking/boleto-payments/cancel-a-boleto-payment) |
| Read | [`GET .../pix/{pixId}`](https://developers.portao3.com.br/api-reference/banking/pix-payments/get-a-pix-payment) | [`GET .../boleto/{boletoId}`](https://developers.portao3.com.br/api-reference/banking/boleto-payments/get-a-boleto-payment) |

What differs for a boleto:

* **The amount is usually known after creating** — the `amount` you sent, or else what the boleto asks for today (`txnUpdatedAmount`, or its face value when that is `0`). Send `category` at creation too and you can go straight to step 3; otherwise — or when the boleto states no amount at all — set them with `PUT`, which also lets you change the amount, the day or the custom fields.
* **A confirmed boleto is `PAID` right away** — there is no `CONFIRMED` step. Once an approval request is approved, the payment becomes `PAID` (or `SCHEDULED`, for a later day), or `FAILED` if the bank refuses it.
* **What a policy sees**: `subjectType` is `BOLETO` — so a policy can govern boleto payments only — the beneficiary (`payee`, `payeeDocument`) is the recipient (`creditParty`), who the boleto was issued to is `debitParty`, and `daysToDueDate` counts the days to the boleto's due date.
* **The day to pay**: the approval deadline is 21:00 (São Paulo time) of the day the payment is for — today, unless you set `scheduledAt`. A bank boleto can only be scheduled for its due date (or the next business day, when it falls on a weekend or holiday; any business day when it has no due date).
* **Notifications**: subscribe to the `BANK_SLIP_PAID` [webhook](https://developers.portao3.com.br/guides/webhooks.md), sent when the boleto is paid.

The same errors, with the boleto's codes:

| Status | Pix `code` | Boleto `code` |
| - | - | - |
| `403` | `PIX_REQUIRES_APPROVAL` | `BOLETO_REQUIRES_APPROVAL` |
| `403` | `PIX_POLICY_DENIED` | `BOLETO_POLICY_DENIED` |
| `403` | `PIX_APPROVAL_NOT_REQUIRED` | `BOLETO_APPROVAL_NOT_REQUIRED` |
| `403` | `PIX_PENDING_APPROVAL` | `BOLETO_PENDING_APPROVAL` |
| `409` | `PIX_NOT_REQUESTABLE` | `BOLETO_NOT_REQUESTABLE` |
| `409` | `PIX_STATUS_NOT_REQUESTED` | `INVALID_BANK_SLIP_STATE` |
| `409` | `PIX_EXPIRED` | `BOLETO_EXPIRED` |
| `422` | `PAYMENT_PARAMETERS_MISSING` | `PAYMENT_PARAMETERS_MISSING` |
| `422` | `CUSTOM_FIELD_IS_REQUIRED` | `CUSTOM_FIELD_INVALID_VALUE` — a boleto reports an empty required custom field with this code |
| `503` | `POLICY_EVALUATION_UNAVAILABLE` | `POLICY_EVALUATION_UNAVAILABLE` |

## Next steps

> [card] [Send a Pix payment](https://developers.portao3.com.br/guides/send-pix.md)
>
> Pay by Pix key, QR code or bank details, step by step.

> [card] [Pay a boleto](https://developers.portao3.com.br/guides/pay-boleto.md)
>
> Pay a bank boleto or a utility bill from its barcode.

> [card] [Receive webhooks](https://developers.portao3.com.br/guides/webhooks.md)
>
> Get notified when a payment goes out.


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