Skip to main content

Deposits (Pix-In)

A deposit is an immediate charge: you create a PIX QR Code, the player pays it from any bank app, and LB Pay notifies you so you can credit the wallet.

API: POST /v1/pix/deposit/immediate-charge, GET /v1/pix/deposit/immediate-charge/{chargeId}

The flow​

Creating the charge​

curl --request POST \
--url "https://api.sdb.lbpay.com.br/v1/pix/deposit/immediate-charge" \
--header "Authorization: Bearer $TOKEN" \
--header 'content-type: application/json' \
--data '{
"externalId": "3f2b1c4e-9a7d-4e21-b8f0-5c6d7e8a9b01",
"amount": 5000,
"expiresIn": 600,
"pixKey": "YOUR_OPERATOR_PIX_KEY",
"expectedPayer": { "taxId": "12345678909" }
}'

amount is an integer in cents — 5000 is R$ 50,00. pixKey is the destination key, yours, identifying the account being credited.

A 201 response carries the chargeId, the copy-and-paste payload in brCode, and status PENDING.

Expiration must match your interface​

expiresIn is the QR Code lifetime in seconds. The most common deposit bug is a mismatch between this value and the countdown shown to the player.

A desynchronised timer rejects valid payments

If the QR Code expires in 300 s but your interface shows a 10-minute countdown, players who pay at minute 7 are rejected — and they experience it as your platform taking their money and failing.

Use at least 600 seconds, and drive the interface countdown from expiresAt returned by the API rather than from a hardcoded constant.

Send your own identifier​

Put your internal transaction or player identifier in externalId, and anything else you need in metadata. Both come back on the statement, so reconciliation becomes a join instead of a guess — see Reconciliation.

Confirming the payment​

Credit only on pixChargePaid

Never credit a wallet because a QR Code was displayed, because the player says they paid, or because a screen was reached. The pixChargePaid webhook — or a GET returning PAID — is the only authorisation to move balance.

If no confirmation arrives within 60 seconds, query the charge directly. Webhooks can be lost; see Contingency polling.

Charges that are not paid​

A charge stays PENDING until it is paid or reaches expiresAt. Two rules follow:

  • Do not cancel and recreate a charge without checking its current status. A player may pay a QR Code you already considered abandoned.
  • A failed payment attempt does not cancel the QR Code. The player can try again against the same charge until it expires — so a single charge may see several attempts before one settles. Design the credit path around "exactly one pixChargePaid per charge", not around "one attempt per charge".

An error webhook is not the end of the charge​

When an attempt fails you receive pixChargeRejected. Look at what it actually carries:

{
"event": "pixChargeRejected",
"status": "pending",
"rejectedReason": "ACCOUNT_MISMATCH"
}

The status is pending, not a terminal value. The event reports a rejected attempt, not a closed charge.

Do not close the charge on this event

Your system must accept pixChargeRejected without treating it as an outcome, keep the charge open, and keep waiting for the real ending — pixChargePaid or pixChargeExpired.

Closing it here discards a deposit the player is likely to retry, and the payment then arrives with nothing on your side expecting it.

Optional payer checks​

expectedPayer lets you declare, when creating the charge, who you expect to pay it. LB Pay then validates the incoming payment against what you declared. Both checks are optional — you enable them by sending the corresponding field.

CheckFieldWhat it verifies
Same payerexpectedPayer.taxIdThe CPF that paid the QR Code is the same one that generated it
Same bank accountexpectedPayer.bankAccountsThe account used to pay is one of the accounts you sent in the payload
{
"expectedPayer": {
"name": "Player Full Name",
"taxId": "12345678909",
"bankAccounts": [
{
"bankCode": "12345678",
"branchCode": "0001",
"accountNumber": "1234567",
"accountType": "CACC",
"personType": "NATURAL_PERSON"
}
]
}
}

Send only taxId to check the payer, only bankAccounts to check the account, or both. Omit expectedPayer entirely and no payer validation is applied.

Declare what you already know

If the player is logged in, you already know their CPF and their registered accounts. Declaring them costs nothing and turns a reconciliation problem into a rejection at payment time, which is far cheaper to handle.

CPF Shield — third-party payments​

CPF Shield is an optional flag. When enabled, it blocks a deposit paid from a CPF different from the one that generated the charge.

It exists because third-party payment is a real scenario in this market — a legal guardian or a family member may pay for the player — and regulation requires the operator to decide whether that is acceptable.

Payer CPFOutcome
Same as the player'sAccepted, wallet credited
Different, and allowed by your configurationAccepted, wallet credited
Different, and not allowedRefused at settlement — the payment does not go through
A refused payment is not a reversal

The block happens at settlement: the money never leaves the payer's account, so there is nothing to credit and nothing to undo. You receive pixChargeRejected, and the charge stays payable until expiresAt — see Charges that are not paid.

You declare the expected CPF in expectedPayer.taxId when creating the charge. On withdrawals the equivalent rule is stricter and has no shield: a destination CPF that differs from the player's is rejected with 422 IGAMING_CPF_MISMATCH — see Withdrawals.

Testing​

In staging, simulate a player paying an open charge:

curl --request POST \
--url "https://api.sdb.lbpay.com.br/v1/pix/mock/simulate-payment" \
--header "Authorization: Bearer $TOKEN" \
--header 'content-type: application/json' \
--data '{
"chargeId": "THE_CHARGE_ID",
"receiverCnpj": "YOUR_RECEIVING_CNPJ"
}'

Both fields are required. The amount and payer details are recovered from the charge.