Security best practices
Your integration moves money, so it deserves the same care as a payment card integration. These practices protect you and your customers.
Protect your secret keys
- Keep keys in server-side configuration or a secrets manager. Never put them in front-end code, mobile apps, logs or version control.
- Use separate keys per system, with only the scopes each one needs.
- Add an IP allowlist to live keys, especially keys with
payouts:write. - Rotate keys when someone with access leaves, and immediately if you suspect a leak. Revoke keys you no longer use.
- Turn on two-factor authentication for every dashboard user. It is required to create live keys.
Trust only verified status
- Fulfil orders only from a verified
payment.completedwebhook or fromGET /payments/{id}, never from the customer reaching yoursuccess_url. - Compare
received_amountandcurrencywith what you expected. Treatunderpaidas not fully paid. - Look up orders by your own
referenceand ourid. Do not trust identifiers supplied by the browser.
Verify every webhook
- Check the HMAC signature over the raw body with a constant-time comparison.
- Reject timestamps older than 5 minutes to block replayed requests.
- Make handlers idempotent: remember processed event IDs.
- Serve your webhook endpoint over HTTPS. This is required in live mode.
Safe requests
- Send an
Idempotency-Keywith everyPOSTand reuse it on retries. - Handle amounts as decimal strings or integer minor units, never floating-point.
- Never let customers set fees or amounts that your server has not checked. The API rejects any request that tries to set a fee.
Payouts
- Build payout requests only from destinations your users registered and confirmed, for example by email confirmation.
- Check the address format and network before sending. Crypto payouts to a wrong address cannot be reversed.
- Watch
payout.failedandpayout.rejectedevents and alert your team.
What we do on our side
- API secrets are stored only as hashes; webhook secrets are encrypted at rest.
- Provider credentials are kept server-side only: in environment variables or encrypted in our database. They are never sent to browsers.
- Provider callbacks are verified by signature, and status is confirmed with the provider before any balance change.
- Every balance change is a balanced double-entry ledger record, protected against double spending with database transactions and locks.
- Sensitive admin actions are audit-logged, and live payouts can require manual approval.
Reporting a vulnerability
If you find a security issue, please contact us privately before disclosing it.