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

FieldNotes
orderIdRequired. Used as orders.order_id.
amountRecommended. Stored in cents.
currencyRecommended. Example: ZAR.

Flow

  1. The API forwards the request to the configured payments service.
  2. The API stores a pending order row in the orders table.
  3. 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.