Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developers.ligdicash.com/llms.txt

Use this file to discover all available pages before exploring further.

After the invoice is created, the response_text field of the response contains the URL of the LigdiCash payment page. This is the URL you must open so the customer can choose their operator and complete the payment. The opening mode depends on your context: web application, native mobile, or hybrid.

Iframes are blocked

LigdiCash blocks the loading of its payment page in an <iframe>. Never embed the URL in an iframe — the page will not display.Always open the link in a real navigation context: same tab, new tab, popup, or native WebView.
This block is enforced server-side through the X-Frame-Options and Content-Security-Policy headers. It is not a bug — it is a deliberate security measure against clickjacking.

The 4 opening modes

ModeRecommended contextImplementation
Same tabWeb — linear flow with no state to keepwindow.location.href = url
New tabWeb — user keeps the current page openwindow.open(url, '_blank')
PopupWeb — modal UX, automatic return to the pageAnti-blocker pattern (see below)
Native WebViewiOS / Android — native mobile applicationDetect return URLs to close
Triggering a window.open() after a network request is systematically blocked by modern browsers: it is not considered a direct user action. The two-step solution:
  1. Open about:blank synchronously on click, before any await
  2. Navigate to the payment URL after receiving the API response
JavaScript
async function startPayment(order) {
  // Step 1 — open the popup immediately on click (synchronous)
  const popup = window.open("about:blank", "ligdicash-payment", "width=500,height=700");

  try {
    // Step 2 — create the invoice
    const response = await fetch(
      "https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/create",
      {
        method: "POST",
        headers: {
          Apikey: process.env.LIGDICASH_API_KEY,
          Authorization: `Bearer ${process.env.LIGDICASH_API_TOKEN}`,
          Accept: "application/json",
          "Content-Type": "application/json",
        },
        body: JSON.stringify(order),
      }
    );

    const data = await response.json();

    if (data.response_code === "00") {
      // Step 3 — navigate within the already-opened popup
      popup.location.href = data.response_text;
    } else {
      popup.close();
      console.error("Invoice creation failed:", data.response_text);
    }
  } catch (err) {
    popup.close();
    throw err;
  }
}
This pattern works on all modern browsers (Chrome, Firefox, Safari, Edge). The key is that window.open() must be called in the same synchronous execution flow as the click handler.

WebView pattern (native mobile)

On iOS and Android, open the payment URL in a native WebView rather than in the system browser. This lets you detect the end of the flow and close the WebView automatically. Principle: intercept every navigation in the WebView and compare the URL with your return_url and cancel_url.
import { WebView } from "react-native-webview";

export function PaymentWebView({ paymentUrl, onSuccess, onCancel }) {
  const handleNavigationChange = (navState) => {
    const { url } = navState;

    if (url.startsWith("https://myapp.com/payment/success")) {
      onSuccess(); // always confirm server-side afterwards
    } else if (url.startsWith("https://myapp.com/payment/cancel")) {
      onCancel();
    }
  };

  return (
    <WebView
      source={{ uri: paymentUrl }}
      onNavigationStateChange={handleNavigationChange}
    />
  );
}
For a complete implementation including React Native and Flutter, see Mobile integration.

Detecting the user’s return

When LigdiCash redirects the customer to your return_url or cancel_url, it indicates that the payment flow on the LigdiCash side is finished. This is not proof of a successful payment.
Never consider a payment validated based on the redirect to return_url alone. A customer can modify the URL manually, or the redirect can occur following a timeout.Always verify the status through the confirm endpoint, or wait for the callback notification.
Recommended behavior on receiving return_url:
  1. Display an intermediate screen “Verifying payment…”
  2. Call your backend, which calls confirm with the token stored at creation
  3. Display the final result (success / failure / pending)