Skip to main content

Simulation endpoints

Five sandbox endpoints drive the test journeys. They use your normal token, AccountId header and collections permissions. They return 404 in production.

EndpointUse it whenWhat it changesWhat it does not do
POST /v1/collections/simulate-paymentYou want a quick success by bank transfer, card or crypto, without opening checkoutCreates a payment and moves the request to PAID or PART_PAID. Bank transfer: also completes the payment and credits the wallet at once, with the full webhook lifecycle. Card: completes the payment and sends the full lifecycle, but a simulated card payment does not add to the sandbox wallet balance. Crypto: credits the wallet and sends payment.completed only when the request reaches PAIDUse a real checkout quote. Mix payment methods on one request. Pay more than the remaining balance.
POST /v1/collections/simulate-crypto-depositYou want to test the real checkout quote: pending deposits, split deposits, quote timeoutsWith PENDING: records a detected deposit only, no funds, no webhooks. With CONFIRMED: updates received funds and the request status, sends the confirmation webhooksCredit the wallet. Send a blockchain transaction. Accept a new deposit on an expired quote. A deposit already detected can still be confirmed with its original depositId.
POST /v1/collections/simulate-payment-completionConfirmed deposits exist and you want the wallet creditedSimulates provider settlement, credits the wallet, sends payment.completed, creates a payout if the request has payout detailsComplete a partly paid quote that is still open. Complete a rejected payment. Reopen an expired request.
POST /v1/collections/simulate-expiryYou want a time limit to pass nowMoves one expiry clock into the past, then applies the normal expiry rulesSettle money. Extend a deadline. Reopen a request.
POST /v1/collections/simulate-payoutA completed payment has a payout and you want to approve, reject, pay or fail itRuns the production approval or bank-result path for that payout and sends its webhookCreate a payout. Skip a step, for example PAID while still awaiting approval.

Expiry targets​

targetMovesResult
CRYPTO_QUOTEThe quote's expiryNo new deposits on that quote. Nothing else changes.
PAYMENT_DEADLINEThe point where new payments stop, 15 minutes before expiresAtCheckout refuses new payments. Started payments can finish.
PAYMENT_REQUESTexpiresAtThe request becomes EXPIRED and sends payment_request.expired, unless a payment is still confirming.

PAYMENT_DEADLINE and PAYMENT_REQUEST need a HOSTED_PAGE or EMBEDDED request. A PAYMENT_LINK request never expires.

Payout outcomes​

Payout statusoutcomeBecomesWebhook
PENDING_APPROVALAPPROVEDINITIATEDpayout.initiated
PENDING_APPROVALREJECTEDFAILEDpayout.failed
INITIATEDPAIDPAIDpayout.paid
INITIATEDFAILEDFAILEDpayout.failed

Any other combination is refused with a 400 that names the current status and, when there is one, the outcome to send first. For example, PAID on a PENDING_APPROVAL payout tells you to send APPROVED first. PAID and FAILED are final: repeating the same outcome returns alreadyProcessed: true, and the other outcome is refused. Add failureReason to record why a payout was rejected or failed.

Choosing the crypto deposit amount​

Fields in simulate-crypto-depositResult
No amount fieldsPays what is left on the quote
"percentageOfRemaining": 50Pays half of what is left. More than 0, at most 100, up to 6 decimals.
"cryptoAmount": 10.25Pays exactly 10.25 tokens of the quote's cryptocurrency

Send a percentage or an exact amount, not both. "What is left" means the quote amount minus all pending and confirmed deposits on that quote.

Retrying safely​

  • Same depositId retries the same deposit, or moves it from PENDING to CONFIRMED. The quote and amount do not change. A confirmed deposit never goes back to pending.
  • New depositId creates a new deposit. It needs an open quote and an UNPAID or PART_PAID request.
  • Repeating a successful deposit call returns alreadyProcessed: true. Repeating a successful completion call returns alreadyCompleted: true. Repeating a payout outcome the payout already reached returns alreadyProcessed: true. None of them adds money or sends webhooks again.
  • Repeating an expiry call never extends a deadline or reopens an expired request. It runs the expiry check again, so a request that stayed open earlier, for example while a deposit was pending, can expire on the retry. The response reports the current status and clocks.
  • If a deposit, completion or expiry call times out, retry with the same IDs or read the current status. Do not invent a new depositId.
  • simulate-payment has no ID. If it times out, read the payment request first. Each call that succeeds creates a new payment.

Errors​

CodeMeaningWhat to do
400The request is valid JSON but the action is not allowed now: closed quote, amount too large, wrong expiry target, payment not ready to completeRead the message. Fix the body, or do the earlier scenario step first.
404Payment request, payment or quote not found for this accountCheck the reference and the AccountId header.

What you cannot simulate yet​

ResultTodayWhat to do instead
payment.failedNo simulatorNothing in sandbox. In production, record the failed attempt and read the request's current status. A failed card attempt does not cancel the request, and the payer can try again.
A payout on a simulated bank transferPayout is created and payout.pending_approval or payout.initiated is sent, but the payment does not show it and simulate-payout cannot find or approve itUse CARD or crypto for payout tests. In production, bank transfer payouts work normally.
payment_request.cancelledNo simulatorNothing in sandbox.
Card declined or 3DS challengeNot in the simulatorUse test card numbers on the hosted payment page.
Payer sends more than the amountRejected by the simulatorNothing in sandbox.
document.validation_warningsNo simulatorNothing in sandbox.
Connection accepted, declined or revokedNo simulatorNothing in sandbox.

If you need one of these, tell your Hubpay contact.