POST
/payment
Create a payment
Send your payment creation payload here. Include an order identifier so the row can be matched later by the webhook.
Expected request fields
| Field | Notes |
|---|---|
orderId | Required. Used as orders.order_id. |
amount | Recommended. Stored in cents. |
currency | Recommended. Example: ZAR. |
Flow
- The API forwards the request to the configured payments service.
- The API stores a pending order row in the
orderstable. - The webhook updates the row when payment status changes.
Webhook
Register this URL in the payment provider dashboard:
/payment/webhook
Webhook payload shape
{
"event": "payment.succeeded",
"payment": {
"id": 123,
"externalId": "ORDER-1001",
"tenantId": "tenant-uuid",
"status": "succeeded",
"amount": 1999,
"currency": "ZAR",
"checkoutId": "checkout_abc"
},
"original": { }
}
Database schema
CREATE TABLE IF NOT EXISTS orders ( id INT AUTO_INCREMENT PRIMARY KEY, tenant_id VARCHAR(100) NOT NULL, order_id VARCHAR(255) NOT NULL, payment_id INT NULL, status VARCHAR(50) NOT NULL DEFAULT 'pending', amount INT NOT NULL DEFAULT 0, currency CHAR(3) NOT NULL DEFAULT 'ZAR', metadata JSON NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY uq_order (tenant_id, order_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Webhook logs table
This table stores each incoming webhook message as text for debugging.
CREATE TABLE IF NOT EXISTS payment_webhook ( id INT AUTO_INCREMENT PRIMARY KEY, tenant_id VARCHAR(100) NULL, event VARCHAR(100) NULL, message TEXT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
The metadata column stores the webhook payload for audit and debugging.