veza/docs/PAYMENTS_SETUP.md

4.4 KiB
Raw Blame History

Payments Setup (Hyperswitch + Mollie)

This guide explains how to configure Hyperswitch and Mollie for payment processing in Veza.

Overview

  • Hyperswitch: Payment orchestration layer (self-hosted or cloud)
  • Mollie: Payment processor (cards, iDEAL, etc.) configured in Hyperswitch
  • Flow: Backend creates order → Hyperswitch creates payment → Frontend shows payment form → User pays via Mollie → Webhook updates order

Prerequisites

1. Start Hyperswitch (Local Development)

Hyperswitch runs as an optional Docker profile. Start it with:

docker compose --profile payments up -d

This starts:

  • hyperswitch_postgres Hyperswitch database
  • hyperswitch Hyperswitch router on port 18081

Verify:

curl http://localhost:18081/health

2. Hyperswitch Control Center

Option A: Hyperswitch Cloud (app.hyperswitch.io)

  1. Sign up at https://app.hyperswitch.io
  2. Create a merchant account
  3. Obtain API Key and Publishable Key from Settings → Developers
  4. Configure webhook URL: https://your-domain.com/api/v1/webhooks/hyperswitch

Option B: Self-Hosted Control Center

If using a self-hosted Control Center, follow the Hyperswitch documentation to obtain API keys and configure webhooks.

3. Configure Mollie in Hyperswitch

  1. In Hyperswitch Control Center, go to Connectors
  2. Add Mollie
  3. Enter your Mollie API key:

Mollie test cards: https://docs.mollie.com/overview/testing

4. Backend Environment Variables

Add to veza-backend-api/.env:

# Hyperswitch
HYPERSWITCH_ENABLED=true
HYPERSWITCH_URL=http://localhost:18081
HYPERSWITCH_API_KEY=your_api_key_from_control_center
HYPERSWITCH_WEBHOOK_SECRET=whsec_xxx

# Checkout success redirect (used in return_url)
CHECKOUT_SUCCESS_URL=http://localhost:5173/purchases

For Docker, use http://hyperswitch:8080 as HYPERSWITCH_URL.

5. Frontend Environment Variables

Add to apps/web/.env.local:

VITE_HYPERSWITCH_PUBLISHABLE_KEY=pk_test_xxx

Use the publishable key from Hyperswitch Control Center (Settings → Developers).

6. Webhook Configuration

Hyperswitch must be able to reach your webhook endpoint:

  • Local dev: Use a tunnel (ngrok, etc.) and set webhook URL to https://your-tunnel.ngrok.io/api/v1/webhooks/hyperswitch
  • Production: https://your-domain.com/api/v1/webhooks/hyperswitch

The webhook is public (no auth). Signature verification is done via HYPERSWITCH_WEBHOOK_SECRET.

7. Test Flow

  1. Start backend and frontend
  2. Add items to cart
  3. Go to checkout
  4. Fill billing details and click "Proceed to payment"
  5. Backend creates order and returns client_secret
  6. Hyperswitch payment form appears
  7. Use Mollie test card or iDEAL
  8. On success, webhook updates order and creates licenses
  9. User is redirected to /purchases

8. Simulated Payments (No Hyperswitch)

When HYPERSWITCH_ENABLED=false or Hyperswitch is not configured:

  • Orders are completed immediately (simulated payment)
  • Licenses are created without real payment
  • Useful for local development only — never use in production

9. Production Checklist

CRITICAL: Real payments require HYPERSWITCH_ENABLED=true. With false, orders complete without payment (dev/simulated only).

  • Set HYPERSWITCH_ENABLED=true in production
  • Use Mollie live API key
  • Use Hyperswitch production keys (pk_prd_, sk_prd_)
  • Set CHECKOUT_SUCCESS_URL to production domain
  • Configure webhook with production URL
  • Verify webhook signature in handler (Phase 7)
  • Ensure HYPERSWITCH_WEBHOOK_SECRET is set and kept secret
  • Set VITE_HYPERSWITCH_PUBLISHABLE_KEY at build time for frontend

Troubleshooting

Hyperswitch not starting

  • Check hyperswitch_postgres is healthy
  • Ensure port 18081 is free
  • See Hyperswitch logs: docker compose logs hyperswitch

Payment form not showing

  • Verify VITE_HYPERSWITCH_PUBLISHABLE_KEY is set
  • Check backend returns client_secret in CreateOrder response
  • Ensure HYPERSWITCH_ENABLED=true and API key are set

Webhook not received

  • Ensure Hyperswitch can reach your webhook URL (no localhost in production)
  • Check webhook secret matches
  • Inspect backend logs for webhook errors