Skip to main content
Process card payments directly from your server, without redirecting the customer to a hosted page. 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.
Between an authorization and capture you can also void if needed to release the hold. After a capture you can refund.

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.
StatusMeaning
CREATEDCreated and queued for processing.
PENDINGBeing processed.
AUTHORIZEDFunds held, not yet captured.
CAPTUREDFull authorized amount captured.
PARTIALLY_CAPTUREDOnly part of the authorization was captured.
VOIDEDAuthorization reversed before capture.
AUTHORIZATION_REVERSEDAuthorization reversed by the system.
EXPIREDAuthorization expired before capture.
FAILEDProcessing failed.
REFUNDEDFully refunded after capture.

Before you begin

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).
curl https://{{url}}/v1/payments \
  -H "x-api-key: $LITE_API_KEY" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 10000,
    "currency": "SAR",
    "payment_instrument": { "id": "e835c96f-3ede-47ff-85e3-3515b7ac125f" },
    "capture_options": { "capture_mode": "MANUAL" },
    "order": { "reference": "ORD-123456", "amount": 10000, "currency": "SAR" },
    "customer": { "email": "john.doe@email.com", "first_name": "John", "last_name": "Doe" },
    "device": {
      "ip": "192.168.1.100",
      "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
      "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9",
      "language": "en-US",
      "screen_height": 1080,
      "screen_width": 1920,
      "color_depth": 24,
      "timezone": -180,
      "java_enabled": false,
      "java_script_enabled": true
    }
  }'

Key request fields

FieldRequiredNotes
amountYesMinor units, minimum 1.
currencyYesISO 4217.
deviceYesBrowser and device data for 3DS and risk. All listed sub-fields are required.
payment_instrument.idConditionalA stored instrument’s UUID. Use this to charge a saved card.
payment_instrument.encrypted_instrument_dataConditionalEncrypted inline card data, as an alternative to a stored instrument.
capture_options.capture_modeConditional when capture_options is sentINSTANT or MANUAL. Default is MANUAL.
processing.processing_typeConditionalREGULAR, CARD_ON_FILE, or UNSCHEDULED_CARD_ON_FILE.
processing.initiatorConditionalCARD_HOLDER (customer present) or MERCHANT (merchant-initiated).
threeds.forceNoForce 3DS regardless of the risk engine assessment.
threeds.dataNoPre-authenticated 3DS results, if you ran 3DS yourself on different rails.
order, customer, metadata, channel_id, return_infoNoOrder detail, customer detail, your own metadata, channel, and redirect URLs for flows that need a 3DS redirect.

Response

{
  "payment": {
    "id": "baf6a8e2-0c89-46ef-9ca5-faa65b99bcd5",
    "status": "PENDING",
    "merchant_reference": "ORD-123456"
  },
  "_links": {
    "self": { "href": "/v1/payments/baf6a8e2-...", "method": "GET" },
    "capture": { "href": "/v1/payments/baf6a8e2-.../capture", "method": "POST" },
    "void": { "href": "/v1/payments/baf6a8e2-.../void", "method": "POST" },
    "refund": { "href": "/v1/payments/baf6a8e2-.../refund", "method": "POST" }
  }
}
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:
curl https://{{url}}/v1/payments \
  -H "x-api-key: $LITE_API_KEY" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 4999,
    "currency": "SAR",
    "payment_instrument": {
      "id": "e835c96f-3ede-47ff-85e3-3515b7ac125f",
      "agreement_id": "a499c5c1-35e8-448c-b0f1-9c5a9527eba4"
    },
    "processing": { "processing_type": "CARD_ON_FILE", "initiator": "MERCHANT" },
    "capture_options": { "capture_mode": "INSTANT" },
    "device": { "...": "required as above" }
  }'
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.

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.
curl https://{{url}}/v1/payments/{payment_id}/capture \
  -H "x-api-key: $LITE_API_KEY" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 10000, "metadata": { "is_final": true } }'

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.
curl https://{{url}}/v1/payments/{payment_id}/void \
  -H "x-api-key: $LITE_API_KEY" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Customer requested cancellation" }'

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.
curl https://{{url}}/v1/payments/{payment_id}/refund \
  -H "x-api-key: $LITE_API_KEY" \
  -H "x-idempotency-key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 5000, "reason": "Customer returned item" }'

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.
curl "https://{{url}}/v1/payments/{payment_id}?include=instrument,operations" \
  -H "x-api-key: $LITE_API_KEY"
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.

Errors

CodeMeaning
400The request is invalid, or the action isn’t allowed in the payment’s current state (for example, capturing a payment that was never authorized).
401Authentication failed. The API key or token is missing or invalid.
403Blocked by security policy, including a payer whose country doesn’t match the client region.
404No payment matches the given ID.
500An unexpected server error. Retry with exponential backoff.