Security

Read this if you're integrating in production. The short version: pin everything you can.

API keys

  • Treat the secret like a password. Put it in a secret manager, never commit it, never log it.
  • Use one key per integration role and scope it down to the minimum needed (read-only for reporting, write for the integration server).
  • Add an IP allowlist on every production key.
  • Set a tight per-key rate limit. A leaked key with rate-limit 60 is much less dangerous than 6000.
  • Rotate keys on every staff change.
  • 5 failed attempts → 1 hour lockout. The lockout is per-key, so an attacker can't lock out other keys by guessing.

Webhooks

  • Verify the Swap-Pay-Signature header — never trust an unsigned event.
  • Reject events older than 5 minutes (replay window).
  • Always dedupe by event_id. Retries reuse the same id.
  • Use HTTPS endpoints with strict TLS — we refuse to send to http://, RFC1918, loopback, link-local.
  • Respond 2xx within 10 seconds. Slow replies trigger retries and eventual dead-letter.
  • If your endpoint accumulates 20 consecutive failures, we auto-pause the webhook. Re-enable in the cabinet.

Hosted checkout

  • The payment_url contains an HMAC; tampered URLs return 404. Send your customer the full URL exactly as we return it.
  • The page sets a strict Content-Security-Policy, X-Frame-Options: DENY, and frame-ancestors 'none'. Don't iframe it.
  • Customer data: we store the email hash for matching only; we don't expose your customer IDs publicly.

Money safety

  • Use raw minor units in your storage. Never store amounts as floats.
  • The exact amount on the hosted checkout includes the service fee. Wrong-amount transfers go to manual review.
  • Every payout and refund waits for operator approval — the broadcast doesn't happen until a human signs off.
  • Ledger is hash-chained per (merchant, asset). Reconciliation runs every 6 hours; drift fires a critical alert.

Customer redirect

  • success_url / fail_url must be HTTPS.
  • Don't include secrets in the redirect target — the customer can see and share the URL.
  • Verify the payment status on your server side via webhook (or GET /invoices/:id) before fulfilling the order. The redirect alone is not authoritative — it's a UX shortcut.

2FA

Enable TOTP on every cabinet account, especially anyone with admin role. Cabinet sessions are 30-day cookies; a leaked cookie without 2FA is a full takeover.