---
url: /docs/payable-managed-wallet.md
description: >-
  Pay a Brazilian boleto or PIX code from a BlindPay-custodied wallet, with no
  on-chain approval and no wallet prompt.
---

This tutorial pays a Brazilian bill from a [managed wallet](/learn/customers), a wallet BlindPay custodies on the customer's behalf. Because BlindPay controls the wallet, there is no `approve` call and no signature to collect: quote the bill, commit the quote, done.

If the funds live in a wallet your user controls, you need the approval step instead: see [Payable with EVM](/payable-evm).

The examples below use `base_sepolia` and `USDB` since they're the development network and test token. Swap in the matching production network and token (`USDC` or `USDT`) when you go live.

This is the shape most "the platform holds the stablecoins" products want: your user pastes a bill and it gets paid, with no wallet interaction at any point.

This path is API only. The BlindPay dashboard pays payables from a connected wallet, so use the API when the funds are in a managed wallet.

## Prerequisites

You also need:

1. A [customer](/learn/customers) with `kyc_status: "approved"`
2. A managed wallet for that customer, funded with enough stablecoin to cover the bill
3. A real boleto linha digitável or PIX copia e cola code to pay

## Pay the bill

### Quote against the managed wallet

Pass `wallet_id` instead of a bare `network`. That pins the quote to the managed wallet, and the address you commit with has to match it.

```js [index.js]
const quoteResponse = await fetch(
  'https://api.blindpay.com/v1/instances/in_000000000000/payable-quotes',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      receiver_id: 're_000000000000',
      type: 'boleto',
      payload: '34191790010104351004791020150008191070026000',
      wallet_id: 'wa_000000000000',
      token: 'USDB',
    }),
  }
)

const quote = await quoteResponse.json()

// Resolved from the rail, not from your user's expectations.
console.log(quote.amount, quote.beneficiary_name, quote.due_date)
```

The response still includes a `contract` object. Ignore it here: it exists for external wallets, and a managed wallet needs no approval.

### Commit the quote

`sender_wallet_address` is the managed wallet's own address. BlindPay recognises it as custodied and moves the funds internally rather than running an ERC-20 `transferFrom`.

```js [index.js]
const response = await fetch(
  'https://api.blindpay.com/v1/instances/in_000000000000/payables',
  {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      payable_quote_id: quote.id,
      sender_wallet_address: 'THE_MANAGED_WALLET_ADDRESS',
    }),
  }
)

const payable = await response.json()
```

The payable is born in `processing`, with no signature collected from anyone.

### Track it to settlement

A PIX code usually completes in under a minute. A boleto settles on a banking day, so `scheduled_date` on the quote already told you when. Subscribe to `payable.complete` for every terminal outcome, and `payable.update` for changes while it is still in flight.

An insufficiently funded managed wallet fails during collection, not at commit time, so the payable is created and then fails. Check the wallet's balance against `sender_amount` before committing if you want to catch that earlier.

## Related

* [Payable quotes](/payable-quotes): what the quote resolves and why it can refuse a code
* [Payable with EVM](/payable-evm): the same flow from a wallet your user controls
* [Payables](/payables): lifecycle, webhooks and the banking calendar
