Create an online payment session

Creates an instalment order and returns the hosted payment URL to redirect the customer to.
This is the first call of every online checkout. Requires scope orders:write.

The journey. The order is created awaiting checkout (status: "AwaitingCheckout") and the
customer completes it on the hosted page: phone verification, identity (Nafath), the credit decision,
plan choice, contract and the first instalment. Nothing is decided at this call — a first-time
customer is never refused here. The page opens in the language of your Accept-Language header
(Arabic by default). When the customer finishes, the order is Confirmed, your webhook fires
(order.confirmed), and the customer is sent to your merchantUrl.success; a decline, an expiry (the
page is valid for two hours) or a cancellation goes to failure / cancel.

Store the returned installmentId (the Qasimha order id) against your own orderReferenceId —
all later order operations (capture, fulfil, refund) use it.

Example request (abridged):

{
  "orderReferenceId": "MERCHANT-ORDER-12345",
  "totalAmount": 1200.00,
  "currencyCode": "SAR",
  "countryCode": "SA",
  "description": "Order #12345",
  "paymentType": "pay_by_instalments",
  "instalments": 4,
  "items": [
    { "referenceId": "SKU-1", "name": "Wireless Headphones", "type": "physical",
      "quantity": 1, "unitPrice": 1200.00, "totalAmount": 1200.00 }
  ],
  "consumer": { "firstName": "Noura", "lastName": "Al-Shammari",
    "phoneNumber": "+9665XXXXXXXX", "email": "[email protected]" }
}

Example response (201):

{
  "success": true,
  "code": "SESSION_CREATED",
  "data": {
    "installmentId": "0d3f...e823",
    "providerSessionId": "sess_...",
    "paymentUrl": "https://.../checkout/...",
    "status": "AwaitingCheckout"
  }
}

Return URLs (optional): merchantUrl { success, failure, cancel, notification } — where the
hosted checkout sends the shopper afterwards. Each URL must be absolute, at most 1024 characters
and carry no fragment; https, http only on localhost / 127.0.0.1, or a custom app scheme
(myshop://…) for a mobile app. success and failure go together; cancel defaults to
failure; notification is reserved and refused. The page appends orderId, orderReferenceId
and status (confirmed on success; declined, expired or failed on failure; cancelled) to
the URL's own query string. A return is a navigation, not a proof — confirm with
GET /merchant/orders/{orderId} before treating the order as paid.

The basket has to add up. Every line is stored as you send it — sku, type, imageUrl,
taxAmount and discountAmount included — and the amounts are reconciled before anything is
financed:

  • item.totalAmount = quantity × unitPrice − item.discountAmount
  • totalAmount = Σ item.totalAmount + taxAmount + shippingAmount − discountAmount

Both to the halala. quantity must be at least 1, no amount may be negative, and currencyCode
must be SAR.

Idempotency: send an Idempotency-Key header (a fresh UUID v4 per order attempt) and reuse it
on retries — a retry replays the original answer (Idempotent-Replay: true) instead of creating a
second order. 409 REQUEST_IN_PROGRESS while the first attempt is still running (retry shortly);
422 IDEMPOTENCY_KEY_REUSED if the same key is sent with a different body.

Errors: 400 VALIDATION_ERROR (field details in errors, including which line failed),
401 missing/invalid key, 403 key lacks orders:write, 409 MERCHANT_SUSPENDED,
429 rate limited.

400 MERCHANT_REQUIRED — the order is always created against a merchant and assessed by that
merchant's policy. An API key or a portal token identifies its own merchant, so any merchantId
in the body is ignored. A back-office admin token carries no merchant and must name one.

409 DUPLICATE_ORDER_REFERENCE — orderReferenceId is already in use. This is the double-submit
answer: when the existing order is yours, data carries its installmentId and paymentUrl, so
send the shopper back to the checkout already open rather than creating a second order.

422 ORDER_DECLINED — only on a deployment still running the earlier external-provider journey,
where the decision was made at creation: the order was created but not approved, so there is no
session to pay. On the hosted journey the decision is made on the page, so 201 always carries a
paymentUrl.

Recent Requests
Log in to see full request history
TimeStatusUser Agent
Retrieving recent requests…
LoadingLoading…
Body Params
string | null
double
double
double
double
string | null
string | null
string | null
string | null
int32
items
array of objects | null
items
consumer
object
shippingAddress
object
billingAddress
object
riskAssessment
object
uuid | null
decisionFeatures
object | null
merchantUrl
object
string | null
string | null
Responses

Language
Credentials
URL
LoadingLoading…
Response
Click Try It! to start a request and see the response here! Or choose an example:
application/json