MagicPayments Integration Guides

Brazil Pix Gate

Pay-inPay-outBRLPix

Accept Pix pay-ins on a hosted QR page and send Pix payouts to a CPF key in Brazilian Real (BRL).

When to use it

The Brazil Pix Gate accepts Pix pay-ins on a MagicPayments-hosted page — the payer enters their identification (name, CPF, e-mail, phone), then the page shows a Pix QR code and the "Pix Copia e Cola" string; the payer completes the transfer in their banking app — and sends Pix payouts to a CPF Pix key. All amounts are in BRL (Brazilian Real, 2 decimal places — so 10000 means 100.00 BRL). Individuals only: payers and payout recipients are identified by CPF (CNPJ is not supported).

OperationRailHow the integration looks
Pay-inPix (QR / Copia e Cola)Create an invoice, redirect the payer to the hosted page.
Pay-outPix key (CPF)Server-to-server call to the wallet-account payout endpoint.
Limits

Pay-ins and payouts accept 50 – 5,000 BRL per operation. In minor units that is 5000500000.

Prerequisites

You need your signing credentials from Getting started, a pay-in gate_id for Brazil Pix, and a pay-out cascade_id enabled for BRL Pix payouts. Your account manager provides both. First-time and repeat depositors may be routed through separate gates — if so, your account manager gives you two gate_ids and tells you which is which.

Pay-in — hosted Pix QR page

The payer never touches your servers with their payment details. You create an invoice; we host the page.

  1. Create the invoice Call the gate endpoint with your gate_id and the amount in BRL minor units.
  2. Redirect the payer Send the customer's browser to the invoice_url we return. Our page collects the payer's name, CPF, e-mail and phone, then shows the Pix QR code and the "Copia e Cola" string with a countdown; the payer completes the transfer in their banking app.
  3. Receive the result The transfer is matched automatically — the payer does not confirm anything on the page. We call your callback_url on every status change; you can poll invoice status as a fallback.
POST/api/invoice
Request body
{
  "gate_id": "br-pix-gate",
  "invoice": {
    "invoice_id": "order-br-2026-000123",
    "currency": "BRL",
    "amount": 10000,
    "description": "Wallet top-up",
    "ttl_minutes": 30
  },
  "customer": {
    "id": "cust-88130",
    "full_name": "Joao Silva",
    "phone_number": "+5511999999999"
  },
  "workflow_hooks": {
    "callback_url": "https://merchant.example.com/mp/callbacks",
    "return_success_url": "https://merchant.example.com/orders/123/done",
    "return_decline_url": "https://merchant.example.com/orders/123/retry"
  }
}
Python
resp = signed_post("/api/invoice", {
    "gate_id": "br-pix-gate",
    "invoice": {
        "invoice_id": "order-br-2026-000123",
        "currency": "BRL",
        "amount": 10_000,             # 100.00 BRL (2 decimal places)
        "description": "Wallet top-up",
        "ttl_minutes": 30,
    },
    "customer": {
        "id": "cust-88130",
        "full_name": "Joao Silva",
        "phone_number": "+5511999999999",
    },
    "workflow_hooks": {
        "callback_url": "https://merchant.example.com/mp/callbacks",
        "return_success_url": "https://merchant.example.com/orders/123/done",
        "return_decline_url": "https://merchant.example.com/orders/123/retry",
    },
})
invoice = resp.json()
redirect_url = invoice["invoice_url"]   # send the payer here
Response
{
  "request_id": "0f0b1d2e-...",
  "request_status": "success",
  "invoice_id": "62051f64-9a79-4edb-8a9e-95c86c55ee4e",
  "merchant_invoice_id": "order-br-2026-000123",
  "invoice_status": "unpaid",
  "invoice_url": "https://stage.example-mp.com/public/invoice/62051f64-.../gate",
  "message": "Invoice (Gate PayIn) with internal uid=62051f64-... has been created."
}
The QR code expires

The Pix code our page shows is valid for a limited window (typically ~10 minutes) and the page shows the payer a countdown. Set a ttl_minutes that gives the payer time to complete the transfer in their banking app, and lean on the callback rather than tight polling.

The payer must use their own account

The Pix transfer must come from an account linked to the CPF the payer entered on the page. A transfer from someone else's account may not be matched to the payment.

Tracking the pay-in

Look up the invoice by your own id (or our invoice_uid). It reaches paid on success.

POST/api/invoice/status
resp = signed_post("/api/invoice/status", {
    "merchant_invoice_id": "order-br-2026-000123"
})
invoice = resp.json()
# invoice["status"] -> "paid" | "payment_failed" | "expired" | "canceled" | ...
# invoice["actual_payment"]["processing_info"]["amount_acquired"] -> settled BRL minor units

Pay-out — to a CPF Pix key

Payouts go server-to-server. The destination is the recipient's CPF used as their Pix key (11 digits, no dots or dashes). Use the wallet-account payout endpoint with a cascade_id enabled for BRL payouts.

POST/api/payment/payout/wallet_account
Request body
{
  "cascade_id": "br-pix-payout",
  "payment": {
    "payment_id": "payout-br-2026-000045",
    "currency": "BRL",
    "amount": 5000,
    "description": "Affiliate payout"
  },
  "wallet": {
    "provider": "pix",
    "wallet_number": "12345678909",
    "full_name": "Richard Roe"
  },
  "customer": {
    "id": "partner-2391",
    "full_name": "Richard Roe",
    "phone_number": "+5511999999999"
  },
  "workflow_hooks": {
    "callback_url": "https://merchant.example.com/mp/callbacks"
  }
}
CPF keys only

wallet.wallet_number must be the recipient's CPF (11 digits). Phone, e-mail and random (EVP) Pix keys are not supported on this rail, and payouts to legal entities (CNPJ) are not accepted. wallet.full_name is the recipient's name and is required.

Python
resp = signed_post("/api/payment/payout/wallet_account", {
    "cascade_id": "br-pix-payout",
    "payment": {
        "payment_id": "payout-br-2026-000045",
        "currency": "BRL",
        "amount": 5_000,              # 50.00 BRL — the payout minimum
        "description": "Affiliate payout",
    },
    "wallet": {
        "provider": "pix",
        "wallet_number": "12345678909",   # recipient CPF, digits only
        "full_name": "Richard Roe",
    },
    "customer": {
        "id": "partner-2391",
        "full_name": "Richard Roe",
        "phone_number": "+5511999999999",
    },
    "workflow_hooks": {"callback_url": "https://merchant.example.com/mp/callbacks"},
})
payout = resp.json()
payout_uid = payout["payment_id"]   # our uid; status starts at "initiated"

Tracking the pay-out

Payouts use the payment status endpoint (not the invoice one). The reason for a rejected payout is delivered with the decline status in your callback.

POST/api/payment/status
resp = signed_post("/api/payment/status", {
    "merchant_payment_id": "payout-br-2026-000045"
})
# resp.json()["status"] -> "success" | "processing" | "decline" | "error"

Testing & go-live