Skip to main content
The sandbox is not a mock. Your charges go out through Infi, a provider of ours, which underneath talks to an Asaas homologation account — the same adapter, the same webhook formats, the same failure modes as production. What changes is the account, not the code. In practice: the provider field comes back "infi", and everything below describes Asaas behaviour, because Asaas is what sits underneath. That is great for fidelity, and its annoying part is over: you close the loop yourself, without anybody’s key. The QR we return in sandbox is a confirmation page of ours — scan it with your phone, press a button, the invoice turns paid.

What comes back on a pix charge

  • pixPayload — render it as a QR, exactly as in production. In sandbox it is the URL of our confirmation page; in production it is the copy-and-paste EMV. Your rendering code is the same either way: it is a QR.
  • pixQrImage — a ready base64 PNG, generated from that same pixPayload. When it comes, use it instead of generating the QR yourself.
  • sandboxConfirmUrl — exists only in sandbox, and it is the explicit marker. If you want a “confirm as if I had paid” button on your test screen, check this field. Never by sniffing whether pixPayload looks like a URL: in production it is EMV, and that kind of check is how a test-only thing leaks into the real checkout.
  • providerPixPayload — Asaas’s EMV, so you can see what production would return. It is not payable in a banking app: it is a homologation account.
  • If pixPayload comes back empty, the charge exists but cannot be paid. Do not invent a QR from id or providerId: the payer’s bank refuses it, and the screen lies to them. Show an error and offer another method.
Pix requires a tax id. Asaas refuses to create the payer without a CPF/CNPJ — without it the charge stops at 422 customer_tax_id_required. Collect and pass taxId with the customer.

Closing the loop: confirming the payment

Two ways, and neither needs a provider key. By scanning, which is the test that counts — it is your real buyer’s flow: render the pixPayload as a QR, point your phone’s camera at it, open it. You land on a page of ours with the amount and a button. Or over HTTP, for your CI:
$SANDBOX_CONFIRM_URL is the sandboxConfirmUrl the charge returned. In the SDK:
Confirming twice is safe: the second answers 200 and does nothing — it is a page people reload. Measured end to end: confirmation → paid in about 3s, with the download grant issued and delivery triggered.
Underneath it is Asaas confirming, not us making it up. Our route does not write “paid” into the database. It calls the sandbox confirm of the provider that created the charge, and that provider’s real webhook comes back through the same path production uses. That is why you see pixTransaction, a deducted fee and a credit date — the charge is real, only the confirmation is yours.
This does not exist in production. The confirmation route is not mounted on a live deployment — it is not protected, it is absent. And sandboxConfirmUrl does not come in the response. If your code calls it, there is nothing to call in production; if your code checks the field, it behaves correctly in both. That is why the marker is a field and not the shape of pixPayload.

How to know they paid

Two ways, and in sandbox only one works today: Registering a webhook in sandbox answers 503 secret_store_unavailable — the secret store is not available to a sandbox tenant. So in sandbox, polling is the way:
The events, signature verification and what to do in production are in webhooks.

What does NOT exist in the sandbox

Things that answer with an error and are not your bug:
  • providers.* → 404. Connecting a PSP (BYOP) is a production-only surface. In sandbox the processor is Infi — a provider of ours, and what shows up in provider on your charges. It runs on Asaas underneath, which explains the formats and errors you see, but the account is ours and there is nothing to connect.
  • webhooks.create → 503, as above.
  • Card may come disabled. The link’s public response carries cardEnabled; when it is false, only pix and boleto are available on that tenant.