Skip to main content
Process card payments directly from your server, without redirecting the customer to a hosted checkout. You send the payment details (or a stored instrument’s ID) to lite. lite authorizes the card, and you capture, void, or refund from your backend. This is the most controllable payment integration option, because card data can pass through your systems, however it carries the highest PCI scope. Use it when you need full control of the payment flow, charge stored cards for recurring subscriptions, or other merchant-initiated payments.

Authorize and capture

A card payment happens in two moves. Authorization checks the card and holds the funds, Capture moves the funds. You choose whether these happen together or separately with capture_mode:
  • INSTANT captures the moment authorization succeeds. Use it when you fulfill immediately, like digital goods.
  • MANUAL authorizes now and waits for you to capture later. Ideal when you ship before charging, so you capture on dispatch.
MANUAL is the default. If you send no capture_options, the payment stops at AUTHORIZED and waits for you. Between an authorization and capture you can also void if needed to release the hold. After a capture you can refund. An authorization does not last indefinitely. If you neither capture nor void before it runs out, the payment moves to EXPIRED, the hold on the customer’s card is released, and you have to create a new payment to charge them. This applies to MANUAL, where you decide when the capture happens.

Payments are asynchronous

Every payment action returns 202 Accepted immediately with a payment id and a status of PENDING. lite processes the work in the background. The 202 means accepted for processing, not succeeded. Get the final outcome by retrieving the payment, following the _links returned on the response, or via your webhook events.

Payment status

A payment reports one of these states. The ones you’ll handle most are AUTHORIZED, CAPTURED, PARTIALLY_CAPTURED, VOIDED, REFUNDED, and FAILED.

Before you begin

Complete sandbox setup first: ask your lite account manager to configure your test connector, turn on Test Mode, create a test API key with payment permissions, activate a routing profile pointing at that connector, and create an e-commerce channel. Sandbox testing covers each step. Authenticate with x-api-key. All examples use https://{{url}}/v1. Amounts are integer minor units (10000 is 100.00 SAR). Optionally, use an x-idempotency-key (a UUID) on every create, capture, void, and refund, so a retried request does not charge twice. Add x-correlation-id (a UUID) to trace a request through logs and support.

Create a payment

POST /v1/payments Required: amount, currency, and device. The device block (IP, user agent, screen, timezone, and so on) is mandatory because it feeds 3DS and risk assessment. Supply the card either as a stored instrument (payment_instrument.id) or as encrypted inline card data (payment_instrument.encrypted_instrument_data).

Key request fields

Response

Keep the id. It identifies the payment for every capture, void, refund, and lookup. The _links tell you which actions are currently allowed, follow them rather than building the URLs by hand. A redirect link appears when the payment needs a 3DS challenge; send the customer there to complete it.

Charging a stored card (card on file)

To charge a saved instrument for a subscription or other merchant-initiated payment, reference the instrument and describe the transaction so it stays scheme-compliant:
Use initiator: MERCHANT for payments you trigger without the cardholder present, and CARD_HOLDER when the customer is actively checking out. The agreement_id links back to the card-on-file agreement you set up when storing the instrument.

3D Secure

Card payments may require cardholder authentication. mada e-commerce payments require it. You have three options. Let the risk engine decide. Send the payment without a three_ds block. If authentication is needed, the response carries a redirect link. Send the customer there and read the outcome when they return, or from the webhook. Force it. Set three_ds.force to authenticate regardless of the risk engine’s assessment. Run it yourself first. Authenticate on separate rails, then pass the result in three_ds.data when you create the payment. The 3DS Authentication guide covers creating an authentication session, handling a CHALLENGE_REQUIRED result, and confirming completion. A customer can abandon the challenge and never return. That is not a decline. Use webhooks and server-side retrieval to find the final status.

Capture an authorized payment

POST /v1/payments/{payment_id}/capture Captures a payment that was authorized with MANUAL. Omit amount to capture the full authorization, or pass a smaller amount for a partial capture. For multiple partial captures, set metadata.is_final to true on the last one to release any remaining authorized funds.

Void an authorized payment

POST /v1/payments/{payment_id}/void Reverses an authorization before it is captured, releasing the hold on the customer’s card. Once a payment is captured, void no longer applies, refund instead. The body is optional; include a reason to record why.

Refund a captured payment

POST /v1/payments/{payment_id}/refund Returns funds after capture. Omit amount to refund the full remaining captured amount, or pass a smaller amount for a partial refund. You can refund multiple times up to the captured total.

Retrieve a payment

GET /v1/payments/{payment_id} Fetch the current state of a payment. Expand related data with include=instrument,operations, where operations lists the authorizations, captures, voids, and refunds applied so far.
The response wraps the payment object and, when relevant, two extras:
  • next_action.redirect: present only when the payment needs the customer sent somewhere, the URL for a 3DS challenge.
  • operations: the audit trail. Each entry is one AUTHORIZE, CAPTURE, REFUND, VOID, or REVERSE, with its own status (PENDING/SUCCESS/FAILURE), amount, and the underlying gateway response codes. This is where you see what happened and why a step failed.
The payment object also reports payment_method, the channel the card ran through: CARD, the wallets (APPLE_PAY, GOOGLE_PAY, SAMSUNG_PAY), network tokens (VTS, SCOF). With include=instrument, the masked card detail (brand, last four, expiry) comes back too. You can also look a payment up by your own order reference with GET /v1/payments/by-order/{order_reference} (same include options), and list a merchant’s payments with GET /v1/payments using pagination and filters.

Receive webhooks

Retrieval gives you the state of a payment when you ask for it. Webhooks tell you when it changes, including after the customer has closed the tab. Configure an endpoint under Settings > Developers > Webhooks and subscribe to the events you need: payment.authorized, payment.captured, payment.partially_captured, payment.refunded, payment.voided, payment.failed. Verify the X-Lite-Signature header against the raw request body before you trust a delivery. Return 200 immediately, then process. Deduplicate on X-Idempotency-Key, because a delivery can arrive more than once. If your endpoint does not return 200, lite retries with exponential backoff for roughly three days. Match the event to your order with data.orderId or data.id. Treat a webhook as a trigger to read the payment server-side, never as proof on its own that money moved. Create a webhook covers signature verification with examples.

Errors

API errors lists every error code lite returns and the errors returned by each API.

Before you go live

Confirm your integration handles all of these in Test Mode.
  • A successful payment, end to end
  • A declined payment, and each error code above
  • A 3D Secure challenge completed, and one abandoned
  • The same request retried with the same x-idempotency-key, charging once
  • A webhook verified, and the same webhook delivered twice without double-processing
  • A payment retrieved by ID and by order reference
  • A capture, a partial capture, a final capture with metadata.is_final, a void, and a refund
  • An action attempted in the wrong state, for example capturing a payment that was never authorized