Skip to content

Bildirim (callback) ​

Bir işlem sonuçlandığında TLHavale, sitenizin bildirim adresine imzalı bir POST isteği gönderir. Bakiye değişikliklerini yalnızca bu bildirime göre yapın.

Adresler ​

Yatırım ve çekim için ayrı birer HTTPS adresi tanımlanır. Adresleri hesap yöneticinize iletin; sitenizin ayarlarına o girer.

İstek ​

http
POST /tlhavale/bildirim HTTP/1.1
Host: siteniz.com
Content-Type: application/json

{
  "transactionId": "dep-2026-000184",
  "status": "CONFIRMED",
  "amount": 1500,
  "hash": "5f1c0e9b7d3a6c1e8f4b2a9d0c7e6f5a4b3c2d1e",
  "type": "deposit"
}
AlanAçıklama
transactionIdTalebi oluştururken verdiğiniz numara
statusİşlemin son durumu (bkz. İşlem durumları)
amountİşlemin son tutarı (TL). Yatırımda talepteki tutardan farklı olabilir.
typedeposit veya withdraw
hashİmza

İmzayı doğrulama ​

hash = sha1( secret + "transactionId=" + transactionId + "&amount=" + amount + "&status=" + status )

secret sizin secKey'inizdir. Hesap yöneticiniz sitenize ayrı bir bildirim anahtarı tanımladıysa o kullanılır. amount metne gelen JSON'daki sayı biçimiyle girer (1500, 1500.00 değil).

İmza tutmazsa isteği işlemeyin ve 401 dönün.

js
const crypto = require("crypto");

function verify(body, secret) {
  const text = `transactionId=${body.transactionId}&amount=${body.amount}&status=${body.status}`;
  const expected = crypto.createHash("sha1").update(secret + text).digest("hex");
  const given = String(body.hash || "");
  return given.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}
php
function verify(array $body, string $secret): bool {
    $text = "transactionId={$body['transactionId']}&amount={$body['amount']}&status={$body['status']}";
    return hash_equals(sha1($secret . $text), (string) ($body['hash'] ?? ''));
}
// Gövdeyi okurken: $body = json_decode(file_get_contents('php://input'), true);
python
import hashlib, hmac

def verify(body: dict, secret: str) -> bool:
    text = f"transactionId={body['transactionId']}&amount={body['amount']}&status={body['status']}"
    expected = hashlib.sha1((secret + text).encode("utf-8")).hexdigest()
    return hmac.compare_digest(expected, str(body.get("hash", "")))

Python'da tutar biçimi

json.loads tam sayıları int olarak okur, bu doğru. Gövdeyi float'a çeviren bir katman kullanıyorsanız 1500.0 metne girer ve imza tutmaz.

Yanıt ve yeniden deneme ​

  • İsteği işledikten sonra HTTP 2xx dönün. Gövde önemli değildir.
  • 15 saniye içinde yanıt gelmezse ya da 2xx dışında bir kod dönerseniz bildirim 1 dakika ve 5 dakika sonra yeniden gönderilir (toplam 3 deneme).
  • Üç deneme de başarısız olursa ekibimiz bildirimi elle yeniden gönderir.

Aynı bildirimi birden çok kez işlemeyin ​

Bildirim yeniden denemeler ve elle gönderimler yüzünden aynı işlem için birden fazla gelebilir. Ayrıca ekip bir kararı düzeltirse aynı işlem için önce REJECTED, sonra CONFIRMED gelebilir.

Önerilen işleyiş:

  1. İmzayı doğrulayın.
  2. transactionId ile kendi kaydınızı bulun ve kilitleyin.
  3. Kayıt zaten CONFIRMED olarak işlendiyse hiçbir şey yapmadan 200 dönün.
  4. Değilse durumu güncelleyin; CONFIRMED ise bakiyeyi amount kadar değiştirin.
  5. 200 dönün.
js
// Express örneği
app.post("/tlhavale/bildirim", express.json(), async (req, res) => {
  if (!verify(req.body, process.env.TLHAVALE_SECRET)) return res.sendStatus(401);

  await db.transaction(async (tx) => {
    const order = await tx.deposits.lockByTransactionId(req.body.transactionId);
    if (!order || order.status === "CONFIRMED") return; // bilinmiyor ya da zaten işlendi
    order.status = req.body.status;
    if (req.body.status === "CONFIRMED") {
      await tx.wallets.credit(order.userId, req.body.amount);
    }
    await tx.deposits.save(order);
  });

  res.sendStatus(200);
});

Sorularınız için hesap yöneticinizle iletişime geçin.