LiderHavale Partner API LiderHavale Partner API
Yatırım ve çekim işlemlerini kendi platformunuza bağlayın.
Yalnızca HTTPS, JSON gövde; kimlik doğrulama gövdedeki
apiKey +
secKey ikilisiyle yapılır.
Integrate deposit and withdraw operations into your own platform.
HTTPS only, JSON body; authentication uses the
apiKey +
secKey pair in the request body.
- Taban adres
- Base URL
- https://api.liderhavale.com
- Taşıma
- Transport
- HTTPS zorunluHTTPS required
- Yöntemler
- Methods
- GET · POST
- Kimlik
- Authentication
- auth.apiKey + auth.secKey
GirişIntroduction
Beş dakikada ilk yatırımı açın. Open your first deposit in five minutes.
⚡ Hızlı başlangıçQuickstart
- Yatırım isteği açınCreate a deposit request
POST /api/payment/deposit/with-partner - Cevaptaki
tokendeğerini alın Take thetokenfrom the response - Müşteriyi ödeme sayfasına yönlendirin
Redirect the customer to the payment page
https://payment.liderhavale.com/?token=${token} - Bildirimi bekleyinWait for the callback
İşlem onaylanınca sunucunuza POST atarız. We POST to your server once the transaction is confirmed.
🔒 GüvenlikSecurity
apiKeyvesecKeydeğerlerini ortam değişkeninde tutun — kaynak koda yazmayın. KeepapiKeyandsecKeyin environment variables — never hard-code them.- Gelen her bildirimin
hashalanını SHA1 ile doğrulayın. Verify thehashfield of every callback with SHA1. - Bildirim ucunuzu aynı işlemi iki kez işlemeyecek biçimde yazın (idempotent). Write your callback endpoint so the same transaction is never processed twice (idempotent).
- İsteğe bağlı: bize IP listesi bildirin, yalnız o adreslerden gelen istekleri kabul ederiz. Optional: give us an IP allowlist and we will only accept requests from those addresses.
Uç noktalarEndpoints overview
Üç iş ucu, dekont bağlantısı ve size attığımız bildirim. Three business endpoints, the receipt link and the callback we send you.
| İşlevFeature | YöntemMethod | YolPath | KimlikAuth |
|---|---|---|---|
| YatırımDeposit | POST | /api/payment/deposit/with-partner |
apiKey + secKey |
| ÇekimWithdraw | POST | /api/payment/withdraw/with-partner |
apiKey + secKey |
| Banka listesiBank list | GET | /api/bank |
GerekmezNone |
| Çekim dekontuWithdraw receipt | GET | /api/dekont/:token |
Bağlantıdaki jetonToken in link |
| Bildirim (biz size)Callback (us → you) | POST | SİZİN_ADRESİNİZYOUR_URL |
SHA1 hash |
Durum kodlarıStatus types
Yatırım ve çekimin alabileceği bütün değerler. Every value a deposit or withdraw can take.
| DurumStatus | AnlamıMeaning | NotNote |
|---|---|---|
| PENDING | Müşteri ya da yönetici onayı bekleniyor Awaiting customer action or admin approval | Ara durumInterim |
| PROCESSING | İstek alındı, ödeme akışı sürüyor Request accepted, payment flow in progress | İlk durumInitial state |
| CONFIRMED | Tamamlandı, bildirim gönderildi Completed, callback sent | Yalnızca bu durum bildirim üretir Only this state fires a callback |
| REJECTED | Yönetici ya da müşteri reddetti Rejected by admin or customer | Sonradan onaylanabilir — aşağıya bakın May be confirmed later — see below |
| TIMEOUT_REJECTED | Süre aşımıyla otomatik reddedildi Auto-rejected after timeout | Sonradan onaylanabilir — aşağıya bakın May be confirmed later — see below |
| SUSPICIOUS | Bizde onaylı, ama bildirim ≈1 saat (12 deneme) iletilemedi Confirmed on our side, but the callback failed for ≈1 hour (12 attempts) | Kurtarılabilir — akışa bakın Recoverable — see the flow |
| FAILED | İşlem sırasında hata Processing error | Kesin durumFinal |
| CANCELLED | Müşteri ya da sistem iptali Cancelled by customer or system | Kesin durumFinal |
CONFIRMED, REJECTED ve
TIMEOUT_REJECTED durumları için gönderilir. SUSPICIOUS bir işlem,
adresiniz yeniden erişilebilir olduğunda kurtarılır ve size CONFIRMED bildirilir.
Callbacks are sent for CONFIRMED, REJECTED and
TIMEOUT_REJECTED. A SUSPICIOUS transaction is recovered once your URL is
reachable again and you receive CONFIRMED.
transactionId için önce
REJECTED/TIMEOUT_REJECTED, sonra CONFIRMED bildirimi alırsınız.
CONFIRMED geldiğinde — önceki red bildirimine bakmadan — müşterinin bakiyesini yükleyin.
Tek kural: aynı işlem için CONFIRMED'ı iki kez işlemeyin.
If the customer pays after the window closed, our payment team can
re-approve the record. You then receive REJECTED/TIMEOUT_REJECTED
followed by CONFIRMED for the same transactionId. When CONFIRMED
arrives, credit the customer regardless of the earlier rejection. The only rule: never process
CONFIRMED twice for the same transaction.
amount alanı her zaman onaylanan (gerçekten gelen) tutardır —
bakiyeyi bu değere göre yükleyin, ilk istediğiniz tutara göre değil.
If the customer sends a different amount, the record is confirmed with the
amount actually received. The amount in the callback is always the confirmed
amount — credit that value, not the amount you originally requested.
Ortam ve kimlik doğrulamaEnvironment & authentication
Adresler, istek biçimi ve anahtarların nasıl gönderildiği. Addresses, request format and how the keys are sent.
| ServisService | AdresAddress | KullanımUsage |
|---|---|---|
| API | https://api.liderhavale.com |
Sunucunuzdan çağırdığınız tüm uçlarEvery endpoint you call from your server |
| Ödeme sayfasıPayment page | https://payment.liderhavale.com |
Müşteriyi ?token= ile yönlendirdiğiniz sayfaWhere you redirect the customer with ?token= |
| DokümantasyonDocs | https://docs.liderhavale.com |
Bu sayfaThis page |
İstek biçimiRequest format
- Gövde JSON, başlık
Content-Type: application/json. En fazla 1 MB. Body is JSON withContent-Type: application/json. Up to 1 MB. - Yalnız HTTPS. Tutarlar Türk lirası, tam sayı ya da iki haneli ondalık. HTTPS only. Amounts are in Turkish lira, integer or two decimals.
- Zamanlar ISO 8601, UTC (
2026-01-01T08:08:26.340Z). Timestamps are ISO 8601, UTC (2026-01-01T08:08:26.340Z). - İş kuralı hataları HTTP 200 +
"status": falseile döner; öncestatusalanına bakın. Business errors return HTTP 200 +"status": false; always checkstatusfirst.
AnahtarlarKeys
apiKeyvesecKeyher istekte gövdedekiauthnesnesiyle gönderilir.apiKeyandsecKeygo in the body'sauthobject on every request.secKeyaynı zamanda bildirim imzasının sırrıdır; tarayıcıya ya da mobil uygulamaya asla koymayın.secKeyis also the callback signing secret; never ship it to a browser or mobile app.- Anahtarlar sızdıysa hesap yöneticiniz panelden yeniler; eskiler anında geçersiz olur. If keys leak, your account manager rotates them in the panel; the old ones stop working immediately.
- IP kısıtı: sunucu IP'lerinizi bildirirseniz hesabınız yalnız o adreslerden istek kabul eder;
listede olmayan adres
402 Unauthorized Access.alır. IP allowlist: send us your server IPs and your account only accepts requests from them; other addresses get402 Unauthorized Access.
YatırımDeposit
Müşteriniz adına yatırım isteği açar. Creates a deposit request on behalf of your customer.
İstek gövdesiRequest body
{
"auth": {
"apiKey": "API_ANAHTARINIZ",
"secKey": "GIZLI_ANAHTARINIZ"
},
"customer": {
"id": "123123", // sizdeki müşteri no
"username": "testmusteri",
"fullName": "Ahmet Yılmaz" // banka hesabındaki ad
},
"transactionId": "456785", // sizde tekil olmalı
"returnUrl": "https://siteniz.com/hesabim",
"amount": 1000
}Başarılı cevapSuccess response
HTTP 200{
"status": true,
"deposit": {
"customer": {
"fullName": "Ahmet Yılmaz",
"username": "testmusteri",
"id": "123123"
},
"transactionId": "456785",
"amount": 1000,
"partner": "6453f2b3c4b1361de57edf90",
"status": "PROCESSING",
"_id": "64c76bfacfe287ddf963ce49",
"created_at": "2026-01-01T08:08:26.340Z"
},
"token": "pZk3_9vQxT2Lm8Rd...",
"paymentUrl": "https://payment.liderhavale.com/?token=pZk3_9vQxT2Lm8Rd..."
}Müşteriyi yönlendirinRedirect the customer
Cevaptaki token ile ödeme sayfasına gönderin.
Bağlantı 10 dakika geçerlidir.
Send them to the payment page with the token from the
response. The link is valid for 10 minutes.
https://payment.liderhavale.com/?token=${token}
Adresi kendiniz kurmak istemiyorsanız cevaptaki
paymentUrl alanını olduğu gibi kullanabilirsiniz — aynı şey.
If you would rather not build the URL yourself, use the
paymentUrl field from the response as is — it is the same thing.
Yatırım işlemleri şu anda kapalıdır ya da
Bu site için yatırım işlemleri kapalıdır cevabı alıyorsanız,
yatırım ya sistem geneline ya da yalnız sizin hesabınıza kapatılmıştır.
Bu cevap HTTP 200 ile gelir — gövdedeki status alanına bakın.
If you get Yatırım işlemleri şu anda kapalıdır or
Bu site için yatırım işlemleri kapalıdır, deposits are off either
globally or for your account only. This response arrives with HTTP 200 —
check the status field in the body.
ÇekimWithdraw
Müşterinin banka hesabına ödeme talebi açar. Submits a payout to the customer's bank account.
İstek gövdesiRequest body
{
"auth": {
"apiKey": "API_ANAHTARINIZ",
"secKey": "GIZLI_ANAHTARINIZ"
},
"customer": {
"id": "123456",
"username": "testmusteri",
"fullName": "Ahmet Yılmaz"
},
"transactionId": "123123",
"iban": "TR760009901234567800100001",
"bank": "65c6525532c59fcd5af4a4b3", // /api/bank içindeki _id
"amount": 1000
}Başarılı cevapSuccess response
HTTP 200{
"status": true,
"withdraw": {
"customer": { "fullName": "Ahmet Yılmaz",
"username": "testmusteri",
"id": "123456" },
"bank": "65c6525532c59fcd5af4a4b3",
"iban": "TR760009901234567800100001",
"transactionId": "123123",
"amount": 1000,
"partner": "6453f2b3c4b1361de57edf90",
"status": "PROCESSING",
"_id": "64c769013f547212cdb46415",
"created_at": "2026-01-01T07:55:45.150Z"
}
}Bu site için çekim işlemleri kapalıdır cevabı alsanız bile
yatırım çalışıyor olabilir; tersi de geçerlidir. IBAN kontrol basamağı bizde
doğrulanır — geçersiz IBAN iş kuralı hatası döner.
Getting Bu site için çekim işlemleri kapalıdır does not mean
deposits are off — and vice versa. We validate the IBAN checksum; an invalid IBAN
comes back as a business-logic error.
Banka listesiBank list
Çekim isteğinde kullanacağınız banka kimliklerini verir. Returns the bank ids you use in withdraw requests.
{
"status": true,
"data": [
{
"_id": "6453f2c8c4b1361de57edfc2",
"name": "GARANTİ BANKASI",
"code": "0062",
"enabled": true,
"created_at": "2026-01-01T18:00:40.003Z",
"updated_at": "2026-01-01T18:00:40.003Z"
},
{
"_id": "64c852d8f7fa26fc12daabb2",
"name": "HALKBANK",
"code": "0012",
"enabled": true,
"created_at": "2026-01-02T00:33:28.724Z",
"updated_at": "2026-01-02T00:33:28.724Z"
}
]
}bank alanına _id değerini
yazın; banka adını değil. Liste değişebilir, günde bir kez tazelemeniz yeter.
Put the _id value in the withdraw request's bank
field, not the bank name. The list can change; refreshing once a day is enough.
BildirimCallbacks
İşlem sonuçlanınca sizin sunucunuza POST atarız. We POST to your server when a transaction is settled.
| AdresDestination | SİZİN_ADRESİNİZYOUR_URL
— bize bildirdiğiniz uç — the endpoint you gave us |
| YöntemMethod | POST application/json |
| Beklenen cevapExpected response | HTTP 200 |
| Zaman aşımıTimeout | 15 saniye15 seconds |
| DenemeAttempts | 5 dakikada bir, en fazla 12 kez (≈1 saat) · sonra SUSPICIOUS
Every 5 minutes, up to 12 times (≈1 hour) · then SUSPICIOUS |
| DekontReceipt | Hesabınızda çekim dekontu açıksa çekim bildirimine receipt_url
eklenir — ödeme makbuzunun kimlik istemeyen bağlantısı (60 gün). İmzaya dahil değildir.
If withdraw receipts are enabled for your account, the withdraw callback carries
receipt_url — an unauthenticated link to the payout receipt (60 days). It is not
part of the signature. |
| Test bildirimiTest callback | Kurulumda adresinize "status": "TEST" ve transactionId'si
TEST- ile başlayan imzalı bir bildirim gönderebiliriz. Bakiye yüklemeyin, yalnız
imzayı doğrulayıp HTTP 200 dönün.
During setup we may send a signed callback with "status": "TEST" and a
transactionId starting with TEST-. Do not credit anything — just verify
the signature and return HTTP 200. |
| DoğrulamaVerification | Gövdedeki hash — SHA1
hash in the body — SHA1 |
İmza (SHA1)Signature (SHA1)
İmzalanan metnin sırası sözleşmenin parçasıdır — alanları başka sırayla dizerseniz hash tutmaz. The order of the signed text is part of the contract — a different field order produces a different hash.
// Node.js const crypto = require("crypto"); const hashRequestSignature = (secret, text) => crypto.createHash("sha1").update(`${secret}${text}`).digest("hex"); // Gelen bildirimi doğrulama function bildirimGecerli(govde, secKey) { const metin = `transactionId=${govde.transactionId}&amount=${govde.amount}&status=${govde.status}`; return hashRequestSignature(secKey, metin) === govde.hash; }
↓ Yatırım bildirimiDeposit callback
{
"transactionId": "456785",
"status": "CONFIRMED",
"amount": 1000,
"hash": "bb2299ae42…",
"type": "deposit"
}↑ Çekim bildirimiWithdraw callback
{
"transactionId": "123123",
"status": "REJECTED",
"amount": 1000,
"hash": "4f1ac07b93…",
"type": "withdraw",
"receipt_url": "https://api.liderhavale.com/api/dekont/…" // yalnız dekont açıksa
}Bildirim akışı ve kurtarmaCallback flow & recovery
Deneme sayacı ve SUSPICIOUS durumu nasıl çalışır.
How the retry counter and the SUSPICIOUS state work.
transactionId, status,
amount, hash, type.
Body: transactionId, status,
amount, hash, type.
CONFIRMED kalır, tekrar denemeyiz.
The transaction stays CONFIRMED; we do not retry.
SUSPICIOUS
The 12th failure (≈1 hour) moves it to SUSPICIOUS
Otomatik denemeyi bırakırız; işlem panelde şüpheli kuyruğuna düşer ve ekibimize haber gider.
We stop retrying automatically; it lands in the suspicious queue and our team is alerted.
CONFIRMED'a döner
On success it returns to CONFIRMED
Kayda kim kurtardığı ve ne zaman düşülür.
Who recovered it and when is written to the audit log.
transactionId'ye bakıp iki kez işlemeyecek biçimde yazın.
From your side you receive exactly one successful callback per
transaction — either on the first attempt or on recovery. Even so, write your
handler to check transactionId and never process it twice.
Dekont bağlantısıReceipt link
Çekim ödendiğinde ödeme makbuzunu müşterinize gösterebilmeniz için. So you can show the payout receipt to your customer once a withdraw is paid.
- Adres, çekim bildirimindeki
receipt_urlalanıdır; kendiniz kurmayın. The address is thereceipt_urlfield of the withdraw callback; do not build it yourself. - Kimlik istemez; jeton tahmin edilemez uzunluktadır. Bağlantıyı yalnız ilgili müşteriyle paylaşın. No auth needed; the token is unguessable. Share the link only with that customer.
- Cevap dosyanın kendisidir:
image/jpeg,image/png,image/webpya daapplication/pdf(en fazla 5 MB). The response is the file itself:image/jpeg,image/png,image/webporapplication/pdf(up to 5 MB). - Dekontlar 60 gün saklanır; sonra bağlantı
404döner. Kalıcı saklamanız gerekiyorsa dosyayı indirip kendinizde tutun. Receipts are kept for 60 days; after that the link returns404. Download and store the file if you need it longer. receipt_urlimzaya dahil değildir; imzayı yinetransactionId,amount,statusile doğrulayın.receipt_urlis not signed; still verify withtransactionId,amount,status.
HatalarErrors
İki ayrı hata sınıfı var — karıştırmak en sık yapılan entegrasyon hatası. There are two distinct error classes — confusing them is the most common integration mistake.
"status": false olarak döner. Sadece response.ok
kontrolü yapan entegrasyonlar bunları başarılı sanıp müşteriye bakiye yükler.
Her zaman gövdedeki status alanını okuyun.
Business-logic errors come back with HTTP 200 and
"status": false in the body. Integrations that only check
response.ok read these as success and credit the customer.
Always read the status field in the body.
HTTP seviyesi hatalarHTTP-level errors
| KodCode | AnlamıMeaning | Örnek cevapExample response |
|---|---|---|
| 401 | Parametre eksikMissing parameters | {"status":false,"message":"Missing parameters apikey or secKey","code":401} |
| 402 | Yetkisiz erişim — anahtar hatalı Unauthorized — wrong key | {"status":false,"message":"Unauthorized Access.","code":402} |
| 403 | Hesap kapalı ya da IP listede değil Account disabled or IP not allowlisted | {"status":false,"message":"Unauthorized Access.","code":403} |
İş kuralı hatalarıBusiness-logic errors
HTTP 200 · status:false| MesajMessage | SebepReason |
|---|---|
Sistem geçici bir süreliğine bakım durumundadır |
Sistem geneli kapalı. Bekleyip tekrar deneyin. System-wide switch is off. Wait and retry. |
Yatırım işlemleri şu anda kapalıdır |
Yatırım sistem geneline kapatılmış. Deposits disabled globally. |
Bu site için yatırım işlemleri kapalıdır |
Yatırım yalnız sizin hesabınızda kapalı. Deposits disabled for your account only. |
Çekim işlemleri şu anda kapalıdır |
Çekim sistem geneline kapatılmış. Withdraws disabled globally. |
Bu site için çekim işlemleri kapalıdır |
Çekim yalnız sizin hesabınızda kapalı. Withdraws disabled for your account only. |
Minimum yatırım tutarı X TL'dir |
Tutar alt sınırın altında. Amount below the minimum. |
Maksimum yatırım tutarı X TL'dir |
Tutar üst sınırın üstünde. Amount above the maximum. |
Aynı transactionId ile bir işlem zaten mevcut |
transactionId sizde tekil olmalı.
transactionId must be unique on your side. |
Şu anda bu tutar için uygun yatırım hesabı bulunmuyor, lütfen daha sonra tekrar deneyin |
Bu tutarı alabilecek yatırım hesabı şu an yok (limitler dolu ya da bakımda). Talep açılmaz; müşteriye mesajı gösterip birazdan ya da farklı tutarla denetin. No receiving account can take this amount right now (limits full or maintenance). Nothing is created; show the message and let the customer retry later or with another amount. |
Geçersiz IBAN |
TR + 24 rakam ve kontrol basamağı doğrulanır. TR + 24 digits; the checksum is validated. |
Müşteri bilgileri eksik (id, username, fullName) |
Üç alanın üçü de zorunlu. All three fields are required. |
Tamamlanmamış yatırım talepleriniz var. Lütfen önce onları sonuçlandırın |
Aynı müşterinin (username) aynı anda en fazla 3 açık yatırımı olabilir. Önceki talep sonuçlanınca ya da süresi dolunca yenisi açılır. A customer (username) may hold at most 3 open deposits at once. A new one opens once an earlier one settles or expires. |
Ödeme yöntemine erişiminiz kısıtlanmıştır… |
Müşteri risk nedeniyle engellenmiş. Müşteriye bu mesajı gösterebilirsiniz. The customer is blocked for risk reasons. You may show this message to the customer. |
Seçilen banka şu anda kullanılamıyor |
Çekimdeki banka kapalı; /api/bank listesini tazeleyin.
The withdraw bank is disabled; refresh the /api/bank list. |
Doğru kontrolThe correct check
const cevap = await fetch(url, { method: "POST", headers, body }); const govde = await cevap.json(); // YANLIŞ: iş kuralı hatası da 200 döner // if (cevap.ok) { bakiyeYukle(); } // DOĞRU if (!cevap.ok) throw new Error(`HTTP ${cevap.status}: ${govde.message}`); if (!govde.status) throw new Error(govde.message); // iş kuralı // buraya geldiyseniz işlem gerçekten açıldı musteriyiYonlendir(govde.token);
Hız sınırlarıRate limits
Sınırlar istemci IP'si başına, dakikalık pencereyle sayılır. Limits are counted per client IP over a one-minute window.
| UçlarEndpoints | DakikadaPer minute | AşılıncaWhen exceeded |
|---|---|---|
/api/payment/*, /api/bank | 60 | HTTP 429 · {"status":false,"message":"Too many requests.","code":429} |
Tüm /api (toplam)All of /api (total) | 600 | HTTP 429 |
RateLimit ve Retry-After başlıkları ne kadar beklemeniz gerektiğini söyler.
İsteği aynı transactionId ile birkaç saniye sonra tekrarlayın; ilk istek işlendiyse ikincisi
mükerrer olarak reddedilir, çift işlem oluşmaz. Banka listesini her istekte değil, saatte bir çekip önbellekte tutun.
The RateLimit and Retry-After headers tell you how long to wait.
Retry with the same transactionId after a few seconds; if the first request went through the second
is rejected as a duplicate, so nothing is created twice. Cache the bank list hourly instead of fetching it per request.
Kod örnekleriCode samples
Yatırım açma ve bildirimi doğrulama — kopyalayıp anahtarlarınızı ortam değişkeninden verin. Creating a deposit and verifying the callback — copy and feed your keys from environment variables.
Yatırım açmaCreate a deposit
<?php
$govde = [
'auth' => ['apiKey' => getenv('LH_API_KEY'), 'secKey' => getenv('LH_SEC_KEY')],
'customer' => ['id' => '123123', 'username' => 'testmusteri', 'fullName' => 'Ahmet Yılmaz'],
'transactionId' => 'DEP-' . $siparisNo, // sizde tekil
'returnUrl' => 'https://siteniz.com/hesabim',
'amount' => 1000,
];
$ch = curl_init('https://api.liderhavale.com/api/payment/deposit/with-partner');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 20,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($govde, JSON_UNESCAPED_UNICODE),
]);
$cevap = json_decode(curl_exec($ch), true);
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http === 200 && !empty($cevap['status'])) {
header('Location: ' . $cevap['paymentUrl']); // müşteriyi ödeme sayfasına gönder
exit;
}
// status:false → $cevap['message'] müşteriye gösterilebilir (limit, kapalı yatırım…)
error_log('LiderHavale: ' . ($cevap['message'] ?? "HTTP $http"));const cevap = await fetch("https://api.liderhavale.com/api/payment/deposit/with-partner", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
auth: { apiKey: process.env.LH_API_KEY, secKey: process.env.LH_SEC_KEY },
customer: { id: "123123", username: "testmusteri", fullName: "Ahmet Yılmaz" },
transactionId: `DEP-${siparisNo}`, // sizde tekil
returnUrl: "https://siteniz.com/hesabim",
amount: 1000,
}),
signal: AbortSignal.timeout(20000),
});
const govde = await cevap.json();
if (cevap.ok && govde.status) {
return res.redirect(govde.paymentUrl); // müşteriyi ödeme sayfasına gönder
}
throw new Error(govde.message || `HTTP ${cevap.status}`);curl -X POST https://api.liderhavale.com/api/payment/deposit/with-partner \
-H "Content-Type: application/json" \
-d '{
"auth": { "apiKey": "API_ANAHTARINIZ", "secKey": "GIZLI_ANAHTARINIZ" },
"customer": { "id": "123123", "username": "testmusteri", "fullName": "Ahmet Yılmaz" },
"transactionId": "DEP-1001",
"returnUrl": "https://siteniz.com/hesabim",
"amount": 1000
}'Bildirimi karşılamaHandling the callback
<?php
$b = json_decode(file_get_contents('php://input'), true) ?: [];
$metin = "transactionId={$b['transactionId']}&amount={$b['amount']}&status={$b['status']}";
$beklenen = sha1(getenv('LH_SEC_KEY') . $metin);
if (!hash_equals($beklenen, (string)($b['hash'] ?? ''))) {
http_response_code(401); exit('imza hatali'); // 200 dönmeyin: sahte istek
}
if ($b['status'] === 'TEST') { http_response_code(200); exit('ok'); }
// Aynı bildirim birden çok kez gelebilir: işlemi yalnız BİR kez uygulayın.
$db->beginTransaction();
$islem = $db->kilitleVeGetir($b['transactionId']); // SELECT … FOR UPDATE
if ($islem && $islem['durum'] !== $b['status']) {
if ($b['type'] === 'deposit' && $b['status'] === 'CONFIRMED') {
$db->bakiyeEkle($islem['musteri'], $b['amount']); // DİKKAT: istenen değil, gelen tutar
}
if ($b['type'] === 'withdraw' && $b['status'] === 'REJECTED') {
$db->bakiyeIadeEt($islem['musteri'], $islem['tutar']);
}
$db->durumYaz($b['transactionId'], $b['status']);
}
$db->commit();
http_response_code(200);
echo 'ok';const crypto = require("crypto");
app.post("/liderhavale/bildirim", express.json(), async (req, res) => {
const b = req.body || {};
const metin = `transactionId=${b.transactionId}&amount=${b.amount}&status=${b.status}`;
const beklenen = crypto.createHash("sha1").update(process.env.LH_SEC_KEY + metin).digest("hex");
const esit = beklenen.length === String(b.hash).length &&
crypto.timingSafeEqual(Buffer.from(beklenen), Buffer.from(String(b.hash)));
if (!esit) return res.status(401).send("imza hatali");
if (b.status === "TEST") return res.send("ok");
// Idempotent: aynı durum ikinci kez gelirse hiçbir şey yapmadan 200 dönün.
await db.transaction(async (t) => {
const islem = await t.islemKilitle(b.transactionId);
if (!islem || islem.durum === b.status) return;
if (b.type === "deposit" && b.status === "CONFIRMED") await t.bakiyeEkle(islem.musteri, b.amount);
if (b.type === "withdraw" && b.status === "REJECTED") await t.bakiyeIade(islem.musteri, islem.tutar);
await t.durumYaz(b.transactionId, b.status);
});
res.send("ok"); // 15 sn içinde HTTP 200
});Canlıya geçiş kontrol listesiGo-live checklist
Canlı trafiği açmadan önce her maddeyi deneyerek işaretleyin. Tick every item by actually trying it before opening live traffic.
- Anahtarlar ortam değişkeninde; kaynak kodda ve istemci tarafında yok.Keys live in environment variables; not in source code or client side.
- Bildirim adresiniz HTTPS, herkese açık ve 15 saniye içinde HTTP 200 dönüyor.Your callback URL is HTTPS, publicly reachable and returns HTTP 200 within 15 seconds.
- Hesap yöneticinizden test bildirimi istediniz; imza doğrulandı ve 200 döndünüz.You asked your account manager for a test callback; the signature verified and you returned 200.
- Yanlış imzalı bildirimi reddediyorsunuz (200 dönmüyorsunuz).You reject a wrongly signed callback (you do not return 200).
- Aynı bildirimi iki kez gönderince bakiye bir kez değişiyor.Sending the same callback twice changes the balance once.
- Yatırımda bildirimdeki
amountile bakiye yüklüyorsunuz (istenen tutarla değil).For deposits you credit the callback'samount(not the requested amount). - Önce
REJECTEDgelip sonraCONFIRMEDgelen yatırımı yüklüyorsunuz (tekrar onay).A deposit that first comesREJECTEDand laterCONFIRMEDis credited (re-approval). - Çekimde bakiyeyi talep anında düşüyor,
REJECTEDgelince iade ediyorsunuz.For withdraws you hold the balance on request and refund onREJECTED. "status": falsecevaplarını (limit, kapalı yatırım, mükerrer no…) müşteriye anlaşılır gösteriyorsunuz.You show"status": falseanswers (limit, deposits off, duplicate id…) to the customer clearly.- Banka listesini önbellekte tutuyor, çekim formunda yalnız açık bankaları gösteriyorsunuz.You cache the bank list and only offer enabled banks on the withdraw form.
- Sunucu IP'lerinizi IP kısıtı için hesap yöneticinize ilettiniz (önerilir).You sent your server IPs to your account manager for the allowlist (recommended).
Sık sorulanlarFAQ
Müşteri ödeme yaptı ama bildirim gelmedi.The customer paid but no callback arrived.
Onay ekibimiz ödemeyi hesapta görünce onaylar; bildirim o anda gider. Sunucunuz 200 dönmezse 5 dakikada bir, 12 kez (≈1 saat) yeniden denenir,
sonra işlem SUSPICIOUS olur ve ekibimiz elle yeniden gönderir. İşlem numarasıyla destek isteyin; panelde her denemenin HTTP kodunu görürüz.
Our team confirms once the payment shows in the account; the callback is sent then. If your server does not return 200 we retry every 5 minutes, 12 times (≈1 hour),
then the transaction turns SUSPICIOUS and our team resends manually. Ask support with the transaction id; we see the HTTP code of every attempt.
Müşteri istenenden farklı tutar gönderdi.The customer sent a different amount.
Ekibimiz tutarı gelen havaleye göre düzeltip onaylar; bildirimdeki amount gerçekte yatan tutardır. Her zaman o değeri yükleyin.
Our team corrects the amount to the actual transfer and confirms; the callback's amount is what was really paid. Always credit that value.
Reddedilen yatırım sonradan onaylanabilir mi?Can a rejected deposit be confirmed later?
Evet. Havale geç düşerse ekibimiz işlemi tekrar onaylar ve aynı transactionId ile CONFIRMED bildirimi gider. Kodunuz bu geçişi kabul etmeli.
Yes. If the transfer lands late our team re-approves it and a CONFIRMED callback is sent with the same transactionId. Your code must accept that transition.
Ödeme bağlantısının süresi doldu.The payment link expired.
Bağlantı 10 dakika geçerlidir; ödeme yapılmamışsa işlem 10 dakika sonunda TIMEOUT_REJECTED olur ve bildirilir. Müşteri için yeni bir transactionId ile yeni yatırım açın.
The link is valid for 10 minutes; if unpaid after 10 minutes the transaction becomes TIMEOUT_REJECTED and you are notified. Open a new deposit with a new transactionId.
Aynı müşteri için kaç açık yatırım olabilir?How many open deposits can one customer have?
Sınırlı sayıda: aynı müşterinin (customer.username) sonuçlanmamış yatırımı 3 olunca yenisi Tamamlanmamış yatırım talepleriniz var… hatasıyla reddedilir (HTTP 200, status:false). Önceki işlemler sonuçlanınca yeniden deneyin.
A limited number: once the same customer (customer.username) has 3 unsettled deposits, a new one is rejected with Tamamlanmamış yatırım talepleriniz var… (HTTP 200, status:false). Retry once earlier ones settle.
Test ortamı var mı?Is there a sandbox?
Ayrı bir sandbox yoktur; bunun yerine payment.liderhavale.com adresi bir test alanıdır: API anahtarlarınızı bir kez girin (yalnız tarayıcınızda saklanır), tutarı yazın, "Yatırım talebi oluştur" deyin — istek bu dokümandaki uca gider ve aynı sayfada ödeme ekranı açılır. Çekim talebi de oradan açılır. Callback'inizi denemek için hesap yöneticiniz panelden imzalı TEST bildirimi gönderebilir.
There is no separate sandbox; instead payment.liderhavale.com is a test playground: enter your API keys once (kept only in your browser), type an amount and hit "create deposit" — the request goes to the endpoint documented here and the payment screen opens on the same page. Withdraw requests can be opened there too. To test your callback, your account manager can send a signed TEST callback from the panel.
NotlarNotes
- transactionId sizde tekil olmalı;
aynı numarayla ikinci istek reddedilir. Bizde
(partner, transactionId)ikilisi üzerinde benzersiz indeks var — eşzamanlı iki istek bile geçemez. transactionId must be unique on your side; a second request with the same number is rejected. We keep a unique index on(partner, transactionId), so even two concurrent requests cannot pass. - returnUrl müşterinin ödemeden sonra döneceği adrestir. Boş bırakırsanız ödeme sayfasında "geri dön" düğmesi çıkmaz. returnUrl is where the customer goes after paying. Leave it empty and the payment page shows no "back" button.
- Komisyon yatırım ve çekim için ayrı ayrı, hesap bazında tanımlanır. Değişiklik için hesap yöneticinizle görüşün. Commission is set per account, separately for deposits and withdraws. Contact your account manager to change it.
- Limitler sistem geneli varsayılanlardan gelir; hesabınız için ezilebilir. Boş bırakılan limit sistem değerine düşer. Limits come from system-wide defaults and can be overridden per account. An unset limit falls back to the system value.
- Çekim akışı: talep
PROCESSINGolarak açılır; ödeme ekibi üstlenincePENDINGolur, ödeme yapılıncaCONFIRMEDya daREJECTEDbildirilir. Çekimlerde süre aşımı yoktur. Withdraw flow: the request opens asPROCESSING; it becomesPENDINGonce a payment team takes it, and you receiveCONFIRMEDorREJECTEDafter payout. Withdraws do not time out. - Ödeme bağlantısı 10 dakika geçerlidir. Süresi dolan bağlantı için yeni bir yatırım isteği açın. The payment link is valid for 10 minutes. Open a new deposit request for an expired link.
- Destek için işlem numarasını iletin; panelde o işlemin bize gelen isteği, verdiğimiz cevap ve bildirim denemeleri birlikte görünüyor. For support, quote the transaction id; the panel shows that transaction's incoming request, our response and every callback attempt together.
Sürüm geçmişiChangelog
- v1.2 2026-09
Ortam ve kimlik, dekont bağlantısı, hız sınırları, PHP/Node/cURL örnekleri, canlıya geçiş listesi ve SSS eklendi. Sözleşmede değişiklik yok. Added environment & auth, receipt link, rate limits, PHP/Node/cURL samples, go-live checklist and FAQ. No contract changes.
- v1.1 2026-09
Bildirimde 5 dk arayla 12 deneme;
receipt_url;TESTbildirimi; tekrar onay ve düzeltilmiş tutar notları; yeni iş kuralı hataları. Callback retried 12 times every 5 minutes;receipt_url;TESTcallback; re-approval and corrected amount notes; new business errors. - v1.0 2026-08
Yatırım, çekim, banka listesi ve SHA1 imzalı bildirim. Deposit, withdraw, bank list and SHA1-signed callback.