AntaraPayAPI v1

Testing in Sandbox

Test every flow with fake data: qp_test_ keys, payin and payout scenarios, manual control, and the built-in webhook receiver.

Test everything with fake data

The Sandbox environment is a complete copy of the API that runs on play money. You can act as a merchant from start to finish (create a key, create payins, create payouts, receive webhooks, read balances and journals) without a real customer, bank or AntaraPay operator. Sandbox simulates all of them for you.

Sandbox only

Everything on this page exists only in Sandbox (qp_test_ keys, base URL https://sandbox-api.antarapay.com). The /api/v1/sandbox/* endpoints return 404 in Production, and no real money ever moves.

Step by step

  1. Sign in to the dashboard and switch to Sandbox (environment switch in the header).
  2. Open Integration and generate your webhook key pair and an API key. Sandbox keys start with qp_test_; copy the key, it is shown once. Give it the payins:read, payins:write, payouts:read and payouts:write scopes.
  3. Your account is credited with play money automatically (IDR 10,000,000 the first time). Check it with GET /api/v1/balances, and top it up with POST /api/v1/sandbox/balance/topup.
  4. Create a payin and a payout as described in the Payin and Payout guides. Sandbox settles them by itself after about 10 seconds, based on the amount or account number you send (see the tables below).
  5. Receive the webhooks on your own server, or use the built-in receiver if you do not have one yet.
Is the sandbox ready?
curl "https://sandbox-api.antarapay.com/api/v1/sandbox" \
  -H "Authorization: Bearer $ANTARAPAY_API_KEY"

GET /api/v1/sandbox returns the autopilot settings, the starter balance, and every scenario below with an example amount or account number.

Payin scenarios

The outcome is chosen by the last three digits of the amount. Any other amount is paid successfully.

Amount ends inExampleResult
any other value15000Paid: status SUCCEEDED, the net amount reaches your balance.
40010400Fails: status FAILED.
50010500Expires: status EXPIRED.
60010600Stays AWAITING_PAYMENT so you can control it by hand.

Channels with delayed settlement (for example QRIS_GOPAY) are paid and then released immediately, so you do not wait for the settlement period.

Payout scenarios

The outcome is chosen by the last four digits of recipient.account_number. Your balance is reserved when the payout is created and released again when it fails or is rejected.

Account number ends inExampleResult
any other value1234567890Approved, sent and completed: status SUCCEEDED with a SBX-TRF-... transfer reference.
00001234560000Rejected: status REJECTED.
99991234569999Fails at the bank: status FAILED.
88881234568888Stays PENDING_APPROVAL so you can control it by hand.

Control it by hand

Use these endpoints with the same API key to play the customer, the operator and the bank yourself. They only affect your own payins and payouts, do not need an Idempotency-Key, and respond with 409 when the payin or payout is already in a final state.

EndpointScopeWhat it does
GET /sandboxanySettings, scenarios and examples.
POST /sandbox/balance/topuppayins:writeAdds play money. Body { "amount": "500000" }, between 1,000 and 10,000,000.
POST /sandbox/settlements/releasepayins:writeMakes every waiting settlement available now.
POST /sandbox/payins/{id}/paypayins:writeThe customer pays: SUCCEEDED.
POST /sandbox/payins/{id}/failpayins:writeThe payment fails: FAILED.
POST /sandbox/payins/{id}/expirepayins:writeThe payin expires: EXPIRED.
POST /sandbox/payouts/{id}/completepayouts:writeApproves, sends and completes the payout.
POST /sandbox/payouts/{id}/failpayouts:writeThe bank transfer fails; the funds are released.
POST /sandbox/payouts/{id}/rejectpayouts:writeThe payout is rejected; the funds are released.
Pay a payin that is waiting for payment
curl -X POST "https://sandbox-api.antarapay.com/api/v1/sandbox/payins/$PAYIN_ID/pay" \
  -H "Authorization: Bearer $ANTARAPAY_API_KEY"

Built-in webhook receiver

No server to receive webhooks yet? Let Sandbox be your server. It receives the events, verifies both the Ed25519 and the HMAC signature, and keeps what it got so you can inspect it.

EndpointScopeWhat it does
POST /sandbox/webhook/receiverpayins:writePoints your webhook URL at the built-in receiver.
GET /sandbox/webhook/inboxpayins:readThe events received, with signature_valid, verified_with and the full body.
POST /sandbox/webhook/testpayins:writeSends a signed sample event (type payin, reference TEST-WEBHOOK) to your webhook URL.

Each event has type set to payin or payout; read data.status to know what happened (see the webhook guide).

A complete test run

bash
# 1. Receive webhooks in the built-in inbox
curl -X POST "$BASE/api/v1/sandbox/webhook/receiver" -H "Authorization: Bearer $KEY"

# 2. Create a payin that will be paid by itself
curl -X POST "$BASE/api/v1/payins" \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reference":"ORD-1","amount":"15000","currency":"IDR","channel":"QRIS_QOIN"}'

# 3. About 10 seconds later: status SUCCEEDED, balance increased
curl "$BASE/api/v1/payins/$PAYIN_ID" -H "Authorization: Bearer $KEY"
curl "$BASE/api/v1/balances" -H "Authorization: Bearer $KEY"

# 4. Create a payout that will complete by itself
curl -X POST "$BASE/api/v1/payouts" \
  -H "Authorization: Bearer $KEY" -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"reference":"PO-1","amount":"40000","currency":"IDR","recipient":{"type":"END_USER","bank_code":"BCA","account_number":"1234567890","account_name":"TEST USER"}}'

# 5. Read the webhooks you received and the journal
curl "$BASE/api/v1/sandbox/webhook/inbox" -H "Authorization: Bearer $KEY"
curl "$BASE/api/v1/journals" -H "Authorization: Bearer $KEY"

Failure paths too

Repeat the run with amounts ending in 400 and 500, and with account numbers ending in 0000 and 9999, to make sure your system handles failed, expired and rejected results and that balances come back.