Skip to main content
Local development means running your application on your own machine against the sandbox, with your debugger attached. When you’re ready to run on deployed infrastructure, see Testing stages.

Get sandbox access

  1. Ask your Payward integration contact to invite you to the sandbox Console, at https://console.sandbox.services.payward.com. Also ask them which capabilities are enabled for your account, such as hosted verification or crypto deposits and withdrawals.
  2. In the Console, open API keys and create a key, as described in Authentication. Select the scopes for the flows you’ll test. Each scope’s description in the Console says what it allows, such as add-funds (deposit funds) or withdraw-funds. If a call returns 403, check the key’s scopes.
  3. Ask your Payward contact to allowlist the public IP addresses your developers call the sandbox from, such as your office or VPN egress addresses. Payward blocks API requests from other addresses.
  4. Optionally, restrict the key itself in the Console’s IP Whitelist field. Leave it empty to allow any address that Payward has allowlisted.

Find your account ID

Most endpoints act on an account, identified by account_id. The Console’s Configuration card shows a Client ID, such as AA85 N84G F6ZU IQSY. That’s your user ID, not your account ID. To get your account ID, make a signed call to Get user (GET /v1/users/{user_id}) with the Client ID, without spaces: GET /v1/users/{client_id}. The response lists your accounts in accounts. Use the id of the account named main as account_id. See Users, accounts, and ownership. The script in Check your credentials makes this call for you and prints the account ID.

Configure your client

Store these values in your local environment or a secrets manager.
After you check your credentials, also set PWS_ACCOUNT_ID to the account ID that the check prints. The examples in other guides read it. The Authentication examples use the same variables but call production. To run them against the sandbox, read BASE_URL from PWS_BASE_URL.

Check your credentials

Make three read-only calls:
  1. List webhooks (GET /v1/webhooks) checks your key, secret, and signing code. It needs no account ID, and a new integration gets {"data":[]}.
  2. Get user (GET /v1/users/{client_id}) returns your account IDs.
  3. Get portfolio (GET /v1/accounts/{account_id}/portfolio) checks your access to the main account.
Public endpoints, such as List assets (GET /v1/assets), don’t check signatures. A successful response from them doesn’t confirm that your key, secret, or signing code works.
Save the example as check_credentials.py or check-credentials.mjs. It follows the signing steps in Authentication, including the next_nonce() (nextNonce()) helper that keeps nonces increasing.
Run it with Python 3.9 or later, with requests installed, or with Node.js 22 or later:
These error responses carry only "code": "gateway", with no message saying which check failed.

Receive webhooks on your machine

Payward delivers webhooks to a public HTTPS URL, so it can’t reach localhost directly. To debug a webhook handler locally:
  1. Start your application locally, with your debugger attached.
  2. Expose the local port through a tunneling service of your choice, such as ngrok. It gives you a public HTTPS URL that forwards to your machine.
  3. Register that URL with Register webhook (POST /v1/webhooks) in the sandbox, and subscribe to the events you’re handling. The callback domain must be allowlisted first, so ask your Payward contact to allowlist your tunnel’s domain. Store the signing_secret from the response; you need it to verify deliveries.
  4. Send a test event with Test webhook (POST /v1/webhooks/{webhook_id}/test). The delivery reaches your handler, and your breakpoints fire. To exercise a real flow, trigger it, for example with a simulated conversion deposit, which emits conversion.* events.
  5. If a delivery doesn’t arrive, check List webhook attempts (GET /v1/webhooks/{webhook_id}/attempts) to see whether Payward tried to deliver it and what your endpoint returned.
Many tunneling tools issue a new URL each time they start. When yours changes, update or re-register the webhook. A tunnel with a fixed domain avoids repeating the allowlisting. Deliveries can be repeated, so deduplicate them by the svix-id header, as described in deposit webhook events.

Troubleshoot setup