Ces exemples montrent un handler de callback complet : déduplication, re-vérification et traitement métier. Adaptez les détails (nom de table, logique métier) à votre 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'] ?? '';
// Supporter JSON et form-urlencoded
if (str_contains($contentType, 'application/json')) {
$payload = json_decode($rawBody, true);
} else {
parse_str($rawBody, $payload);
// custom_data arrive en JSON stringifié en 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;
}
// Déduplication
try {
$pdo->exec("INSERT INTO processed_callbacks (transaction_id) VALUES ('$transactionId')");
} catch (PDOException $e) {
// Déjà traité — doublon LigdiCash
http_response_code(200);
exit;
}
// Retrouver le token stocké à la création
$stmt = $pdo->prepare('SELECT token FROM transactions WHERE transaction_id = ?');
$stmt->execute([$transactionId]);
$row = $stmt->fetch();
if (!$row) {
http_response_code(404);
exit;
}
// Re-vérification
$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') {
// Traitement métier
$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);
}
// Déduplication atomique
$inserted = DB::table('processed_callbacks')->insertOrIgnore([
'transaction_id' => $transactionId,
'created_at' => now(),
]);
if (!$inserted) {
return response()->noContent(200);
}
// Retrouver le token stocké
$transaction = DB::table('transactions')
->where('transaction_id', $transactionId)
->first();
if (!$transaction) {
return response()->noContent(404);
}
// Re-vérification
$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);
}
// Déduplication atomique
try {
await db.query(
'INSERT INTO processed_callbacks (transaction_id) VALUES ($1)',
[transactionId]
);
} catch {
// Contrainte d'unicité — doublon LigdiCash
return res.sendStatus(200);
}
// Retrouver le token stocké
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-vérification
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 arrive en JSON stringifié en 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)
# Déduplication atomique
try:
ProcessedCallback.objects.create(transaction_id=transaction_id)
except IntegrityError:
return HttpResponse(status=200)
# Retrouver le token stocké
try:
transaction = Transaction.objects.get(transaction_id=transaction_id)
except Transaction.DoesNotExist:
return HttpResponse(status=404)
# Re-vérification
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)
Les exemples ci-dessus utilisent l’endpoint de confirmation payin redirect. Pour un payout, remplacez l’endpoint par
GET /pay/v01/withdrawal/confirm/?withdrawalToken={token}. Voir Vérifier le statut d’un payout.