Skip to content
MOONIPdocs
IntegrationManual
PTEN
Go to dashboard

Sandbox

The Moonip sandbox lets you exercise a full integration — create a charge, read the QR, poll status, test idempotency — without moving money and without waiting on acquirer credentials.

There is no separate host. Same URL, same contract as production; only the key changes.

#Entering the sandbox

Issue a test key in the dashboard (or through the API-keys endpoint) and use it as usual:

KeyWhat happens
ak_test_...The charge goes to the simulator. Nobody is charged.
ak_live_...The charge goes to the real acquirer.

There is no request-body field to pick the environment — the key decides, and only the key. Sending an environment header by hand changes nothing: the gateway discards it and treats the request as a real charge.

bash
curl -X POST https://api.moonip.io/v1/charges \
  -H "Authorization: Bearer ak_test_YOUR_KEY" \
  -H "Idempotency-Key: order-1234" \
  -H "Content-Type: application/json" \
  -d '{"amount": 15000, "currency": "BRL", "payment_method": "pix"}'

Response (abbreviated):

json
{
  "id": "ch_a4521699-89a6-44a1-adb6-745862875e95",
  "object": "charge",
  "amount": 15000,
  "status": "pending",
  "payment_method": "pix",
  "pix": {
    "br_code": "00020126SANDBOX-PIX-8494424468F862C5DE279BA25204000053039865802BR",
    "qr_code_base64": "data:image/png;base64,iVBORw0KGgo...",
    "expires_at": "2026-07-30T18:14:12.338Z"
  }
}

#What to expect from the artifacts

Every sandbox artifact carries the SANDBOX marker inside its own value — BR Code, barcode, reference. That is deliberate: if one leaks into a screen, an email or a report, the text gives away its origin instead of looking like a real charge nobody can settle.

The QR image is generated normally and renders; scanning it in a banking app fails, because the BR Code is not valid Pix.

Artifacts are deterministic. The same charge always returns the same values. That is what makes retry and idempotency testable: repeating the same Idempotency-Key returns the same charge, not a new one.

#Confirming a sandbox payment

The one outcome you can force is paid, and that is the merchant's self-test lever for webhook end-to-end:

text
POST /v1/payments/{id}/confirm-sandbox

On a charge created with a test key (a sandbox charge), this turns it PAID and fires the normal webhooks — your endpoint receives the same charge.paid delivery it would in production. Response: { "confirmed": true, "status": "PAID" }; an already-terminal charge answers { "confirmed": false, "status": "…", "reason": "ALREADY_TERMINAL" }, and a non-sandbox charge is refused with 400.

The SDKs wrap it as payments.confirmSandbox(id) (node client.payments.confirmSandbox(id), python client.payments.confirm_sandbox(id), php $client->payments->confirmSandbox($id), dotnet client.Payments.ConfirmSandboxAsync(id)). The dashboard's Test environment page does the same, and also simulates a completed payout; those deliveries carry X-Moonip-Test: true (see Test deliveries). The endpoint Test button sends one sample delivery without touching a charge.

#What does not exist yet

Whatever you are testing, count on this:

  • The charge never pays itself. Status stays pending and does not advance with time — it moves only when you confirm it (above). This is deliberate: a simulator that "pays" after N seconds makes tests clock-dependent and blocks the case that matters most, the charge that is never paid and expires.
  • Only paid can be forced. refused, chargeback and other negative outcomes cannot be set through the API. Planned, not built.
  • Pix only on the public API, which is Pix-first today. The simulator internally also covers card, boleto and Multibanco; they surface here as the public contract exposes them.

#Isolation

The sandbox shares the same account and the same ledger as your real operation — it is not a separate environment with its own data. Test charges appear in your listings next to real ones, distinguishable by the SANDBOX marker in the artifact.

If that is a problem for your workflow, create a second account for testing only.


Leaking an ak_test_ key has no financial impact — it cannot charge anyone. Still, treat it as a credential: it reads your account's data.