Skip to content

Getting Started

On this page

Testing

Test invoice and withdrawal state changes with dedicated test keys, signed webhooks, and simulation endpoints that move no real funds.

Test your integration end-to-end in sandbox. Same API surface as production, simulated blockchain, signed webhooks, no real money at risk.

Sandbox vs production

Feature Sandbox Production
Base URL api.paymos.io/v1 api.paymos.io/v1
API Keys pk_test_ / rk_test_ IDs with sk_test_ secrets pk_live_ / rk_live_ IDs with sk_live_ secrets
Transactions Simulated Real blockchain
Webhooks Sent normally Sent normally
Funds No real value Real crypto

Simulating payments

Sandbox payments are not auto-confirmed by a timer. Trigger them explicitly:

POST/v1/sandbox/invoices/:invoice_id/simulate-payment

Body: { "stage": "paid" }stage is one of paid, overpaid, underpay, or cancel. Authenticate it like any other signed /v1 call; it acts on sandbox invoices only, so a production key is rejected with 403 not_sandbox. It fires the same lifecycle and webhook events as a real on-chain payment, so your verification path stays identical between sandbox and production.

Simulating withdrawals

Sandbox withdrawals don't settle on a real chain. Mark a pending sandbox withdrawal as completed to exercise your full payout flow:

POST/v1/sandbox/withdrawals/:withdrawal_id/simulate-completion

No request body. Authenticate it like any other /v1 call with your Payout key; it acts on sandbox withdrawals only. It transitions the withdrawal to completed and emits the same withdrawal.completed webhook as a real on-chain payout, so your reconciliation path stays identical between sandbox and production.

Simulating channel deposits

Sandbox payment channels derive their addresses locally and watch no chain, so deposits are created explicitly:

POST/v1/sandbox/payment-channels/:payment_channel_id/simulate-deposit

Body: { "amount": "100", "currency": "USDT", "network": "TRC20", "stage": "confirmed" }stage is one of confirming, reorged or confirmed and defaults to confirmed. Sign it with your sandbox Payment key; a production key is rejected before anything is created. Every call emits payment_channel.deposit.confirming first, then the terminal event for the stage you asked for, so your webhook path is identical between sandbox and production. See Simulate Channel Deposit for the full contract.

Testing webhooks locally

Expose your local server through a tunnel:

ngrok http 3000

Set the webhook URL in Dashboard → Developer → Webhooks:

https://abc123.ngrok.io/api/paymos-webhook

Webhook playground

The documentation includes a sandbox-only Webhook Playground that runs the real delivery path: it creates a sandbox invoice, drives it to the outcome you picked, and lets the delivery worker call your registered endpoint. Nothing is posted straight to your URL, so signature handling is verified against the same signing and retry code production uses.

  • 01Go to Dashboard → Developer → Documentation in the sandbox environment
  • 02Open Webhooks → Testing, then select Playground
  • 03Pick an event type (invoice.paid, invoice.paid_over, invoice.underpaid, or invoice.cancelled), set the amount and currency, then Simulate
  • 04Check your server logs for the received event and the X-Webhook-Signature header

It needs an active sandbox webhook endpoint and a sandbox Payment key. Production sending is disabled there by design.

Checklist before going live

  • Webhook signature verification works
  • Invoice creation returns correct data
  • Payment flow redirects properly
  • Error handling covers non-2xx responses (4xx validation, 409 conflicts)
  • Idempotency with external_order_id works
  • Switch API key IDs from pk_test_ / rk_test_ to pk_live_ / rk_live_, and secrets from sk_test_ to sk_live_