Sessions

A session represents a single attempt at collecting a payment from a customer. It is the foundation of every minnha integration.

Lifecycle

StatusMeaning
PENDINGCreated but not yet paid.
PROCESSINGCustomer submitted payment; awaiting gateway.
REQUIRES_ACTION3-D Secure or extra step needed.
SUCCESSCaptured.
FAILEDAuthorization declined.
CANCELLEDCustomer abandoned the checkout.
REFUNDED / PARTIALLY_REFUNDEDAfter a refund.

Create a session

bash
POST /api/v1/sessions
X-Api-Key: mp_test_...

{
  "amount": 1000.00,
  "currency": "SAR",
  "description": "Annual tuition fee",
  "includeEnrollmentFees": true,
  "customerEmail": "customer@example.com",
  "customerPhone": "+966512345678",
  "successUrl": "https://yourapp.com/orders/123/success",
  "cancelUrl":  "https://yourapp.com/orders/123/cancel",
  "metadata": { "orderId": "ord_123" },
  "lineItems": [
    {
      "skuItem": "TUITION-2026",
      "description": "Annual tuition fee",
      "amount": 1000.00
    }
  ],
  "expiresInMinutes": 60
}

amount is the total including VAT and must equal the sum of lineItems[].amount when line items are provided.description (optional) is shown on the hosted checkout.customerPhone (optional) triggers an SMS with the description and payment link.includeEnrollmentFees: true is required for Jeel on tuition/enrollment checkouts.

Education merchants: pass lineItems to control VAT invoice lines. See Educational billing for templates, PDF export, and ERP delivery.

Response

json
{
  "transactionId":     "8f8a…",
  "sessionToken":      "sess_abc123…",
  "checkoutUrl":       "https://minnha-checkout.vercel.app/pay/sess_abc123…",
  "amount":            1000.00,
  "currency":          "SAR",
  "status":            "PENDING",
  "description":       "Annual tuition fee",
  "customerPhone":     "+966512345678",
  "smsSent":           true,
  "expiresAt":         "2026-07-01T12:00:00Z",
  "availableGateways": ["JEEL", "MOYASAR", "TABBY"],
  "environment":       "TEST",
  "successUrl":        "…",
  "cancelUrl":         "…"
}

Open the checkout

Pass sessionToken to one of the client SDKs. They handle redirect / popup / iframe and emit a normalised event when the customer is done:

ts
// @minnha/pay-js
import { MinnhaPay } from "@minnha/pay-js";
const result = await MinnhaPay.open({ sessionToken, mode: "popup" });
// result.status: "success" | "failed" | "cancelled" | "requires_action"

Look up a session

The GET /api/v1/sessions/{token} endpoint is public (no API key) — the session token itself is the credential. This is how the hosted checkout page reads the data.

Sessions expire if left unpaid (default 60 minutes, configurable up to 24 hours via expiresInMinutes). Pass customerPhone to send the customer an SMS with the payment link — configure Twilio in production or check API logs locally.

Customising the checkout page

Each merchant can create custom checkout pages (rich content + branding) from Dashboard → Custom Pages. Only one page can be active at a time. If none exists, the default minnha layout is used.

Use {{description}} in your page HTML to show what the customer is paying for (from the session, or the page name as fallback). Also available: {{amount}}, {{currency}}, {{merchantName}}, {{customerEmail}}.