This document outlines the payment system implementation in the Sjoppie API. The system is designed to be modular, allowing for easy integration of multiple payment gateways.
- Overview
- Database Structure
- Payment Gateway Modules
- API Endpoints
- Payment Flow
- Webhook Handling
- Error Handling
- Examples
The payment system consists of several components:
- Payment model and database table
- Payment gateway modules (e.g., Mollie)
- Payment service for business logic
- API endpoints for payment operations
- Webhook handling for payment status updates
The payments table stores all payment information:
payments
├── id
├── customer_id (FK)
├── payment_gateway_id (FK)
├── gateway_payment_id
├── status
├── amount
├── currency
├── description
├── redirect_url
├── webhook_url
├── metadata (JSON)
├── gateway_response (JSON)
├── paid_at
├── expires_at
├── created_at
├── updated_at
└── deleted_atpending: Initial state when payment is createdpaid: Payment successfully completedfailed: Payment failedcancelled: Payment was cancelledexpired: Payment expired
Payment gateways are implemented as modules in app/Modules/PaymentGateways/. Each gateway must implement the PaymentGatewayInterface:
interface PaymentGatewayInterface
{
public function getName(): string;
public function getDescription(): string;
public function getRequiredConfiguration(): array;
public function validateConfiguration(array $configuration): bool;
public function initialize(array $configuration): void;
public function isConfigured(): bool;
public function createPayment(Payment $payment): array;
public function handleWebhook(Payment $payment, array $data): void;
}- Mollie:
app/Modules/PaymentGateways/Mollie/MolliePaymentGateway.php
POST /api/paymentsRequest body:
{
"payment_gateway_id": 1,
"customer_id": 1,
"amount": 10.00,
"currency": "EUR",
"description": "Order #12345",
"redirect_url": "https://your-app.com/order/success",
"metadata": {
"order_id": "12345"
}
}Response:
{
"success": true,
"status": 201,
"data": {
"payment": {
"id": 1,
"customer_id": 1,
"payment_gateway_id": 1,
"amount": "10.00",
"currency": "EUR",
"status": "pending",
"description": "Order #12345",
"redirect_url": "https://your-app.com/order/success",
"webhook_url": "https://api.sjoppie.com/api/payments/webhook/mollie",
"metadata": {
"order_id": "12345"
},
"gateway_response": {
"id": "tr_123456789",
"checkout_url": "https://checkout.mollie.com/payment/...",
"status": "open",
"created_at": "2024-04-25T21:52:54+00:00",
"expires_at": "2024-04-26T21:52:54+00:00"
}
},
"checkout_url": "https://checkout.mollie.com/payment/..."
},
"timestamp": "2024-04-25T21:52:54+00:00"
}GET /api/payments/{id}Response:
{
"success": true,
"status": 200,
"data": {
"id": 1,
"customer_id": 1,
"payment_gateway_id": 1,
"amount": "10.00",
"currency": "EUR",
"status": "paid",
"description": "Order #12345",
"redirect_url": "https://your-app.com/order/success",
"webhook_url": "https://api.sjoppie.com/api/payments/webhook/mollie",
"metadata": {
"order_id": "12345"
},
"gateway_response": {
"id": "tr_123456789",
"status": "paid",
"paid_at": "2024-04-25T21:53:00+00:00"
},
"paid_at": "2024-04-25T21:53:00+00:00",
"created_at": "2024-04-25T21:52:54+00:00",
"updated_at": "2024-04-25T21:53:00+00:00"
},
"timestamp": "2024-04-25T21:53:00+00:00"
}POST /api/payments/webhook/{gateway}The webhook endpoint is automatically configured when creating a payment. The gateway parameter in the URL determines which payment gateway module handles the webhook.
- Client creates a payment through the API
- System creates a payment record and initializes the payment with the selected gateway
- Client receives the checkout URL and redirects the customer
- Customer completes the payment on the gateway's checkout page
- Gateway sends a webhook notification to our API
- System updates the payment status based on the webhook data
The system automatically handles webhook notifications from payment gateways. Each gateway module implements its own webhook handling logic to:
- Verify the webhook signature (if applicable)
- Update the payment status
- Store additional payment details
- Trigger any necessary business logic
The API follows a standardized error response format:
{
"success": false,
"message": "Error message",
"status": 500,
"debug": {
"message": "Detailed error message",
"file": "app/Http/Controllers/Api/PaymentController.php",
"line": 42,
"trace": "..."
}
}Debug information is only included when APP_DEBUG=true.
- First, ensure you have a configured Mollie payment gateway:
INSERT INTO payment_gateways (name, module_name, is_active, is_test_mode, configuration)
VALUES (
'Mollie',
'Mollie',
true,
true,
'{"test_api_key": "test_...", "live_api_key": "live_..."}'
);- Create a payment:
POST /api/payments
{
"payment_gateway_id": 1,
"customer_id": 1,
"amount": 10.00,
"description": "Test Payment",
"redirect_url": "https://your-app.com/payment/success",
"metadata": {
"test": true
}
}- Redirect the customer to the checkout URL:
window.location.href = response.data.checkout_url;- Handle the webhook notification (automatically processed by the system)
GET /api/payments/1The response will include the current payment status and any updates from the payment gateway.
- Always verify payment status through the API before fulfilling orders
- Implement proper error handling for failed payments
- Use test mode when developing
- Keep payment gateway API keys secure
- Monitor webhook notifications for failed payments
- Implement proper logging for payment operations
- Use the metadata field to store relevant order information
- Implement proper error handling for webhook notifications