2026-02-14 20:45:15 +00:00
|
|
|
|
# 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
|
|
|
|
|
|
|
|
|
|
|
|
- Docker and Docker Compose
|
|
|
|
|
|
- Mollie account (https://www.mollie.com/dashboard)
|
|
|
|
|
|
- Hyperswitch API keys (from Control Center or self-hosted)
|
|
|
|
|
|
|
|
|
|
|
|
## 1. Start Hyperswitch (Local Development)
|
|
|
|
|
|
|
|
|
|
|
|
Hyperswitch runs as an optional Docker profile. Start it with:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker compose --profile payments up -d
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
This starts:
|
|
|
|
|
|
|
|
|
|
|
|
- `hyperswitch_postgres` – Hyperswitch database
|
|
|
|
|
|
- `hyperswitch` – Hyperswitch router on port 18081
|
|
|
|
|
|
|
|
|
|
|
|
Verify:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
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:
|
|
|
|
|
|
- **Test**: `test_xxx` from https://www.mollie.com/dashboard/developers/api-keys
|
|
|
|
|
|
- **Live**: `live_xxx` for production
|
|
|
|
|
|
|
|
|
|
|
|
Mollie test cards: https://docs.mollie.com/overview/testing
|
|
|
|
|
|
|
|
|
|
|
|
## 4. Backend Environment Variables
|
|
|
|
|
|
|
|
|
|
|
|
Add to `veza-backend-api/.env`:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 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`:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
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
|
2026-02-15 15:08:49 +00:00
|
|
|
|
- **Useful for local development only** — never use in production
|
2026-02-14 20:45:15 +00:00
|
|
|
|
|
|
|
|
|
|
## 9. Production Checklist
|
|
|
|
|
|
|
2026-02-15 15:08:49 +00:00
|
|
|
|
**CRITICAL**: Real payments require `HYPERSWITCH_ENABLED=true`. With `false`, orders complete without payment (dev/simulated only).
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] Set `HYPERSWITCH_ENABLED=true` in production
|
2026-02-14 20:45:15 +00:00
|
|
|
|
- [ ] 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
|
2026-02-15 15:08:49 +00:00
|
|
|
|
- [ ] Set `VITE_HYPERSWITCH_PUBLISHABLE_KEY` at build time for frontend
|
2026-02-14 20:45:15 +00:00
|
|
|
|
|
|
|
|
|
|
## 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
|