Skip to content

Per-product credential storage

Each uncle-z product manages its own credentials. The gateway operator hands out (public_key, secret, webhook_secret) triples per app; PSP-side credentials (Polar OATs, etc.) you manage on your side.

Per app, three values, generated at provisioning time:

public_key: pk_<24 hex chars>
secret: <64 hex chars>
webhook_secret: <64 hex chars>

Typical pattern: two apps per product (sandbox + live), so you carry six secrets total. Store them outside the repo:

# .env (gitignored, deployment-specific)
PAYMENT_GATEWAY_URL=https://payment.uncle-z.com
PAYMENT_GATEWAY_PUBLIC_KEY=pk_xxx
PAYMENT_GATEWAY_SECRET=xxx
PAYMENT_GATEWAY_WEBHOOK_SECRET=xxx

Rotation: not in-place today. If a secret is compromised, the operator archives the app and provisions a new one. You swap the env, restart, done.

Polar OATs (only if your product hits Polar)

Section titled “Polar OATs (only if your product hits Polar)”

Per product, two OATs (sandbox + live), scoped narrow:

  • read everything
  • write only products + custom_fields

Cannot issue charges, rotate webhook secrets, or modify org settings.

Store outside the repo:

~/.config/<product>/polar-oat-sandbox.txt # chmod 600
~/.config/<product>/polar-oat-live.txt # chmod 600

These tokens are only for product-side product CRUD — creating Polar products, updating prices, etc. They are NOT used at runtime. The gateway has its own runtime token (full scope) on the prod server; not your concern.

Don’t share OATs across products. Don’t commit them. Rotate at the issuing dashboard if you suspect compromise.

What you should NEVER store on the product side

Section titled “What you should NEVER store on the product side”
  • The gateway’s PSP credentials (POLAR_*_ACCESS_TOKEN, NICEPAY_*_MERCHANT_KEY, etc.) — those live in the gateway’s prod env, not in any product.
  • The gateway’s webhook secrets for inbound (PSP→gateway) — those are PSP-side, owned by the operator.
  • Other products’ app credentials — every product gets its own pair.

When the operator hands you credentials for a new product:

  1. Receive: public_key, secret, webhook_secret for sandbox app + same for live app.
  2. Receive: Polar product UUIDs for sandbox + live (per plan), if you’re a Polar product.
  3. Drop into your deployment env (production .env, Docker env, etc.).
  4. Implement request signing using secret.
  5. Implement webhook verification using webhook_secret.
  6. Smoke-test with sandbox creds against payment.uncle-z.com (full E2E with real PSP sandbox).
  7. Flip env to live creds when promoting to production.

The flip from sandbox to live in production is just an env swap + restart on your side — no gateway changes, no operator involvement.