Skip to main content
A API tem dois ambientes e uma URL só. Quem decide onde a requisição cai é o prefixo da chave.

Produção

Chave ps_live_.Cobrança de verdade, saldo de verdade, saque de verdade.

Sandbox

Chave ps_test_.Nada é enviado a banco nenhum. O PIX gerado não é pagável.
O brCode do sandbox não é um código PIX de verdade. Ele volta como SANDBOX_PIX_<paymentId>, uma string sem valor nenhum: não escaneia, não cola em app de banco, ninguém paga por acidente.Se você renderizar isso num QR Code na sua tela de teste, o QR vai existir e não vai funcionar. É esperado.
Os dados são isolados de ponta a ponta. Uma cobrança criada com ps_test_ não aparece para ps_live_, e o saldo de sandbox é calculado só a partir das transações de teste. Se o prefixo da chave não bater com o ambiente em que ela foi criada, a API responde 401 em vez de escolher um ambiente por conta própria.

Simulando pagamento

Como ninguém consegue pagar um PIX de sandbox, você marca como pago pela API:
O status vira paid e o webhook sai para a callbackUrl que você informou na criação, exatamente como aconteceria em produção. Não existe aprovação de ninguém no meio. A chamada só funciona com chave ps_test_ e só alcança cobrança da sua própria conta: com chave ps_live_ a resposta é 403.
Chame simulate-paid duas vezes na mesma cobrança. O status não muda de novo, mas o webhook sai outra vez com o mesmo X-Webhook-Id. É o jeito mais barato de verificar se o seu handler é idempotente antes de precisar disso em produção.
No webhook de simulação o event é sempre payment.paid, mesmo quando você simula uma cobrança psc_. O payload é enxuto: event, paymentId, amountCents, status, paidAt, customer, metadata e sandbox: true.

Conferindo o resultado

GET /v1/sandbox/wallet

Saldo simulado, somado a partir das transações de teste.

GET /v1/sandbox/transactions

Extrato do que você criou em sandbox, com paginação.
GET /v1/wallet também funciona com chave de teste. Nesse caso a resposta vem com "sandbox": true, e disputeBlocked e cryptoBalanceLtc ficam sempre em zero.

O que não roda em sandbox

POST /v1/card-payments depende do provedor de checkout e não é simulado. Teste o cartão direto em produção com um valor baixo.
paymentMethod: "ltc" responde 400 com chave de teste. A cotação e o endereço vêm da rede real, então não há como simular.
Os endpoints de /v1/disputes respondem 404 em sandbox. Contestação nasce de uma transação real.
O saque em sandbox é registrado e dispara os eventos withdrawal.test.requested e withdrawal.test.completed, mas nenhum valor sai.

Indo para produção

Troque a variável de ambiente com a chave. Nada mais muda: mesma URL, mesmos campos, mesmos nomes de evento.
Vale a pena rodar o mesmo teste automatizado nos dois ambientes, com a chave vindo de variável. Se o teste passa com ps_test_ e quebra com ps_live_, o problema está em configuração de conta e não no seu código.