Pluggable payment providers for VMP billing.
| ID | Status | Default enabled |
|---|---|---|
stripe |
Production | Yes |
qerko |
Production (legacy eshop / migration) | Only when listed in tenant settings |
gopay |
Stub (NotImplementedError) |
No |
comgate |
Stub (NotImplementedError) |
No |
Admin settings still store legacy in CSV lists; the registry normalizes that to qerko. D1 subscriptions.provider continues to use legacy for Qerko rows.
payments_enabled_providers and payment_provider_order in admin_settings control which providers are active, e.g.:
- Fresh launch:
stripe - Migrated tenant:
stripe,legacy(parsed asstripe,qerko)
createEnabledProviders(enabledIds, config) returns a Map of configured provider instances. Billing code must resolve the provider from this map — never import Stripe or Qerko SDKs directly.
Each provider exposes capabilities:
newSubscriptions— may onboard brand-new subscribers (Qerko: true when enabled in tenant settings; uses the legacy eshop initial payment / CardOnFile create flow)migrationOnly— only for pre-existing platform subscribers (Qerko: false; relink still works vianeeds_relink+ purchaseId)recurringPayments,refunds,webhooks— feature flags for future UI/guards
Checkout must gate on provider.capabilities.newSubscriptions instead of hardcoded provider IDs. Admins still control whether Qerko appears at checkout via payments_enabled_providers.
- Add
src/providers/<id>/index.tsexportingcreateXProvider(config): PaymentProvider. - Register in
src/registry.tsPROVIDER_FACTORIES. - Wire config in the API composition root (
packages/api/src/paymentProviders.ts). - Add webhook route
/api/payments/webhook/<id>or dispatch by path.
GoPay / Comgate are registered stubs — enable in settings only after real implementations land.
Stub capabilities are set to all false until real implementations land. Treat as placeholder until PSP contracts are finalized.