Payment Gateway Architecture
Gateway-agnostic payment infrastructure for EloSync Central. The Billing Engine talks only to PaymentGatewayInterface. Stripe and Laravel Cashier live exclusively inside StripeGateway.
Components
| Piece | Role |
|---|---|
PaymentGatewayInterface | Contract: checkout, refunds, webhooks, test connection, capabilities, currencies |
GatewayManager | Resolves drivers by payment_gateways.code; binds encrypted config onto the driver |
BillingEngine | Purchase / consolidate / handle normalized GatewayEvent — no Stripe/Cashier imports |
StripeGateway | Cashier Checkout + Stripe SDK + webhook normalization |
CreemGateway | Creem REST (HTTP client) + webhook normalization |
ManualGateway | Synchronous offline settlement |
PaymentGatewayService | Admin enable/disable/default/config/mode/test/logs |
GatewayWebhookController | POST /webhooks/gateways/{code} → driver → Billing Engine |
StripeWebhookController | Cashier-compatible /stripe/webhook + Billing Engine dispatch |
Architecture
Checkout / activation sequence
ER (gateway-agnostic)
payment_methodsis the workspace preferred-method table (tenant_id+is_default). No separateworkspace_payment_methodstable.
Product mapping
Gateways with checkout + subscriptions capabilities (requiresProductMapping()) store provider product/price references in payment_gateway_module_prices. Modules never store Stripe (or any provider) IDs.
Admin API: GET/PUT /payment-gateways/{id}/module-prices. Central UI: Billing → Payment Gateways → Product mapping.
Adding a new gateway
- Implement
App\Billing\Drivers\{Name}Gateway extends AbstractGateway. - Register in
config/core-platform.php→payment_gateways. - Seed a
payment_gatewaysrow (code,driver, capabilities, currencies). - If the gateway needs provider price IDs, implement mapping via
payment_gateway_module_prices(no Module schema changes). - Point provider webhooks to
POST /webhooks/gateways/{code}. - Do not change
BillingEngineor Module catalog fields.