POST /payment Create a payment session

Creates a payment request for the current tenant and stores a pending order row for later webhook updates.

Headers

HeaderRequiredNotes
X-Tenant-IDrequiredTenant that owns the payment
Content-Typerequiredapplication/json

Request Body

FieldTypeRequiredDescription
packageIdnumberrequiredCredit package to purchase
customerNamestringoptionalCustomer display name
customerEmailstringoptionalCustomer email address

Example Request

POST /payment
Content-Type: application/json
X-Tenant-ID: TENANT_ABC

{
  "packageId": 4,
  "customerName": "Test Customer",
  "customerEmail": "customer@example.com"
}

Responses

// 200 OK
{
  "data": {
    "paymentId": 32,
    "redirectUrl": "https://..."
  }
}

Response format

FieldTypeNotes
data.paymentIdnumberInternal payment reference
data.redirectUrlstringCheckout redirect URL
POST /payment/webhook Receive payment webhook events

Receives payment status updates from the provider and updates the matching order row.

Headers

HeaderRequiredNotes
Content-Typerequiredapplication/json

Payload

FieldTypeRequiredDescription
eventstringrequiredWebhook event name
paymentobjectrequiredPayment details from the provider
originalobjectoptionalOriginal provider payload

Example Payload

{
  "event": "payment.succeeded",
  "payment": {
    "id": 123,
    "externalId": "ORD-123",
    "tenantId": "TENANT_ABC",
    "status": "succeeded",
    "amount": 157.5,
    "currency": "ZAR"
  }
}

Persistence

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        DECIMAL(10,2) NOT NULL DEFAULT 0.00,
  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;

CREATE TABLE IF NOT EXISTS orders_webhook (
  id             INT AUTO_INCREMENT PRIMARY KEY,
  tenant_id      VARCHAR(100) NULL,
  event          VARCHAR(100) NULL,
  status         VARCHAR(50) NULL,
  message        TEXT NOT NULL,
  errors         TEXT NOT NULL,
  created_at     DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

Response format

FieldTypeNotes
dataobjectWebhook acknowledgement payload
data.messagestringStatus message