These examples show a complete callback handler: deduplication, re-verification, and business processing. Adapt the details (table names, business logic) to your application.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.
- PHP
- Laravel
- Node.js / Express
- Python / Django
<?php
$rawBody = file_get_contents('php://input');
$contentType = $_SERVER['CONTENT_TYPE'] ?? '';
// Support both JSON and form-urlencoded
if (str_contains($contentType, 'application/json')) {
$payload = json_decode($rawBody, true);
} else {
parse_str($rawBody, $payload);
// custom_data arrives as a stringified JSON in form-urlencoded
if (isset($payload['custom_data']) && is_string($payload['custom_data'])) {
$payload['custom_data'] = json_decode($payload['custom_data'], true) ?? $payload['custom_data'];
}
}
$transactionId = null;
foreach ($payload['custom_data'] ?? [] as $entry) {
if (($entry['keyof_customdata'] ?? null) === 'transaction_id') {
$transactionId = $entry['valueof_customdata'] ?? null;
break;
}
}
if (!$transactionId) {
http_response_code(400);
exit;
}
// Deduplication
try {
$pdo->exec("INSERT INTO processed_callbacks (transaction_id) VALUES ('$transactionId')");
} catch (PDOException $e) {
// Already processed — LigdiCash duplicate
http_response_code(200);
exit;
}
// Retrieve the token stored at creation
$stmt = $pdo->prepare('SELECT token FROM transactions WHERE transaction_id = ?');
$stmt->execute([$transactionId]);
$row = $stmt->fetch();
if (!$row) {
http_response_code(404);
exit;
}
// Re-verification
$params = http_build_query(['invoiceToken' => $row['token']]);
$ch = curl_init("https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm?$params");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Apikey: ' . $_ENV['LIGDICASH_API_KEY'],
'Authorization: Bearer ' . $_ENV['LIGDICASH_AUTH_TOKEN'],
],
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if (($result['status'] ?? '') === 'completed') {
// Business processing
$pdo->exec("UPDATE orders SET status = 'paid' WHERE transaction_id = '$transactionId'");
}
http_response_code(200);
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
class LigdicashCallbackController extends Controller
{
public function handle(Request $request)
{
$transactionId = collect($request->input('custom_data', []))
->firstWhere('keyof_customdata', 'transaction_id')['valueof_customdata'] ?? null;
if (!$transactionId) {
return response()->noContent(400);
}
// Atomic deduplication
$inserted = DB::table('processed_callbacks')->insertOrIgnore([
'transaction_id' => $transactionId,
'created_at' => now(),
]);
if (!$inserted) {
return response()->noContent(200);
}
// Retrieve the stored token
$transaction = DB::table('transactions')
->where('transaction_id', $transactionId)
->first();
if (!$transaction) {
return response()->noContent(404);
}
// Re-verification
$result = Http::withHeaders([
'Apikey' => config('ligdicash.api_key'),
'Authorization' => 'Bearer ' . config('ligdicash.auth_token'),
])->get('https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm', [
'invoiceToken' => $transaction->token,
])->json();
if (($result['status'] ?? '') === 'completed') {
DB::table('orders')
->where('transaction_id', $transactionId)
->update(['status' => 'paid']);
}
return response()->noContent(200);
}
}
import express from 'express';
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post('/callback', async (req, res) => {
const payload = req.body;
const customData = Array.isArray(payload.custom_data) ? payload.custom_data : [];
const entry = customData.find((item) => item.keyof_customdata === 'transaction_id');
const transactionId = entry?.valueof_customdata;
if (!transactionId) {
return res.sendStatus(400);
}
// Atomic deduplication
try {
await db.query(
'INSERT INTO processed_callbacks (transaction_id) VALUES ($1)',
[transactionId]
);
} catch {
// Unique constraint — LigdiCash duplicate
return res.sendStatus(200);
}
// Retrieve the stored token
const row = await db.query(
'SELECT token FROM transactions WHERE transaction_id = $1',
[transactionId]
).then(r => r.rows[0]);
if (!row) return res.sendStatus(404);
// Re-verification
const params = new URLSearchParams({ invoiceToken: row.token });
const verify = await fetch(
`https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm?${params}`,
{
headers: {
Apikey: process.env.LIGDICASH_API_KEY,
Authorization: `Bearer ${process.env.LIGDICASH_AUTH_TOKEN}`,
},
}
);
const result = await verify.json();
if (result.status === 'completed') {
await db.query(
"UPDATE orders SET status = 'paid' WHERE transaction_id = $1",
[transactionId]
);
}
res.sendStatus(200);
});
import json
import os
import requests
from django.db import IntegrityError
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
@csrf_exempt
@require_POST
def ligdicash_callback(request):
content_type = request.content_type or ""
if "application/json" in content_type:
payload = json.loads(request.body)
else:
payload = request.POST.dict()
# custom_data arrives as stringified JSON in form-urlencoded
if isinstance(payload.get("custom_data"), str):
try:
payload["custom_data"] = json.loads(payload["custom_data"])
except (json.JSONDecodeError, TypeError):
pass
custom_data = payload.get("custom_data") or []
entry = next(
(e for e in custom_data if e.get("keyof_customdata") == "transaction_id"),
None,
)
transaction_id = entry.get("valueof_customdata") if entry else None
if not transaction_id:
return HttpResponse(status=400)
# Atomic deduplication
try:
ProcessedCallback.objects.create(transaction_id=transaction_id)
except IntegrityError:
return HttpResponse(status=200)
# Retrieve the stored token
try:
transaction = Transaction.objects.get(transaction_id=transaction_id)
except Transaction.DoesNotExist:
return HttpResponse(status=404)
# Re-verification
result = requests.get(
"https://app.ligdicash.com/pay/v01/redirect/checkout-invoice/confirm",
params={"invoiceToken": transaction.token},
headers={
"Apikey": os.environ["LIGDICASH_API_KEY"],
"Authorization": f"Bearer {os.environ['LIGDICASH_AUTH_TOKEN']}",
},
).json()
if result.get("status") == "completed":
Order.objects.filter(transaction_id=transaction_id).update(status="paid")
return HttpResponse(status=200)
The examples above use the hosted payin confirmation endpoint. For a payout, replace the endpoint with
GET /pay/v01/withdrawal/confirm/?withdrawalToken={token}. See Verify the payout status.