Panel → Geliştiriciler → “API anahtarı al”. Anahtar smk_abcdefghij_plus48chars biçimindedir ve yalnızca bir kez gösterilir. Kaybederseniz yenisini oluşturun: önceki anahtar hemen geçersiz olur.
Tek bir header ekleyin
Authorization: Bearer your_key.
Erişimi doğrulayın
Bakiyeyi sorgulayın. data içeren bir JSON yanıtı geldiyse anahtar kabul edilmiştir.
{
"data": [
{
"asset_id": "usdt", // her zaman usdt — başka bakiye yoktur
"available_atomic": "15000000", // en küçük birimlerle 15 USDT (6 ondalık basamak)
"available": "15", // aynı değer ondalık biçimde
"held_atomic": "0", // tamamlanmamış çekimler için bloke edilen tutar
"held": "0"
}
]
}
İstek başarısız olduysa
Yanıt
Neden
401 unauthorized
Anahtar eksik, boşluk içeriyor veya kesilmiş. Bearer kelimesinden sonra smk_… tanımlayıcısının tamamı gelmelidir.
401 key_inactive
Anahtar iptal edilmiş: yeni bir anahtar oluşturulmuş, ancak istek hâlâ öncekiyle gönderiliyor.
Beş kural
Entegrasyon hatalarının çoğu bu kurallardan birine uyulmamasından kaynaklanır.
1. Tutarları string olarak gönderin
İki alandan birini gönderin: amount — ondalık bir string: "0.001", "15" — ya da amount_atomic — en küçük birimlerle bir tam sayı: 0.001 BTC için "100000". Yalnızca bir alan kullanın. Yanıtlarda her zaman iki biçim de bulunur: amount ile amount_atomic yan yana gelir.
örnek
"amount": "0.001" // geçerli
"amount_atomic": "100000" // bu da geçerli
// ikisi birden — 422
2. asset_id değerini yalnızca /assets yanıtından alın
İzin verilen kodlar: usdt, btc, xmr. Rastgele değerler ve blok gezginlerindeki kimlikler 422 ile reddedilir.
örnek
"asset_id": "btc" // doğru
"asset_id": "BTC" // hata
"asset_id": "bitcoin" // hata
3. Kayıt oluşturan her istekte Idempotency-Key
Denemenin benzersiz kimliğidir. Bağlantı koparsa ve sonuç bilinmiyorsa isteği aynı anahtarla tekrarlayın: ilk sonuç döner, ikinci bir işlem oluşturulmaz. POST /invoices, POST /payments, POST /payouts/preview ve POST /payouts için zorunludur.
örnek
Idempotency-Key: order-42-payment // ilk deneme → 201, oluşturuldu
Idempotency-Key: order-42-payment // tekrar → 200, aynı kaynak
Idempotency-Key: order-42-payment // farklı tutar → 409 conflict
4. Boş alanlar yanıtta yer almaz
Null değerler ve boş string'ler yanıta eklenmez. Henüz ödenmemiş bir ödemede actual_amount, credited_amount ve fee bulunmaz. Anahtarın değerini değil, var olup olmadığını kontrol edin.
örnek
// henüz ödenmemiş ödeme:
{ "payment_id": "pay_…", "status": "awaiting_deposit" }
// credited_amount alanı hiç yer almaz
5. expired durumunda siparişi kapatmayın
expired, transferin hiç gelmeyeceği anlamına gelmez. Adres yaklaşık 6 saat daha izlenir ve geç gelen transfer bakiyeye eklenir. Bakiyeye ekleme yapılan nihai durumlar: confirmed, confirmed_underpaid, confirmed_overpaid.
Senaryolar
Her senaryo tüm döngüyü kapsar: isteklerin sırası, yanıtın yapısı ve alanların anlamı. JSON örneklerindeki yorumlar açıklama içindir, gerçek yanıtlarda yer almaz.
Ödeme alma
Müşteri 60 USD'lik siparişi BTC ile ödüyor
Sipariş: order-42. Yaklaşık 60 USDT almanız gerekiyor; BTC fiyatı yaklaşık 60.000 USD iken müşteriden beklenen tutar 0.001 BTC olur.
1
Kullanılabilir varlıkların listesini alın
Yanıt, varlık kodunu ve decimals değerini, yani ondalık ayırıcıdan sonraki basamak sayısını döndürür.
{
"data": [
{
"asset_id": "btc", // ← sonraki isteklerde bunu kullanın
"symbol": "BTC", // kullanıcıya göstermek için
"network": "bitcoin", // çekimlerde kullanılır
"decimals": 8, // 1 BTC = 100000000 atomik birim
"price_usd": "60000" // yaklaşık değer, teklif için kullanılmaz
},
{
"asset_id": "usdt",
"symbol": "USDT",
"network": "TRON",
"decimals": 6,
"price_usd": "1.00"
}
]
}
2
Kuru 10 dakikalığına sabitleyin
Müşteri ödeme sayfasındayken kuru sabitler. Bu adımda ödeme ya da adres oluşturulmaz, yalnızca teklif hesaplanır. Yanıtta 0.001 BTC karşılığında bakiyeye eklenecek USDT tutarı yer alır.
Müşteriye ağın TRC20 olduğunu söyleyin. Bu adrese başka bir ağda gönderilen USDT bakiyeye eklenmez.
Müşteri istenenden az gönderdi
0.001 BTC bekleniyordu, 0.0009 geldi; örneğin müşterinin cüzdanı ağ ücretini tutardan düştü.
1
Ödemeyi kontrol edin
Gelen tutar expected_amount değerinden azsa ama bakiyeye eklenmek için yine de yeterliyse durum confirmed_underpaid olur ve credited_amount tekliften düşük çıkar. Tutar çok küçükse hiçbir şey eklenmez.
{
"data": {
"payment_id": "pay_01HZX...",
"status": "expired", // süre doldu
"asset_id": "btc",
"expected_amount": "0.001",
"deposit_address": "bc1qexampledepositaddress000000000",
"expires_at": "2026-08-11T18:00:00+00:00"
// actual_amount ve credited_amount yok — hiç transfer gelmedi
}
}
2
Müşteri geç ödedi
Transfer ek izleme süresi içinde gelirse ödeme yine de confirmed durumuna geçer. expired durumunda siparişi silmeyin: gecikmiş olarak işaretleyin ve sorgulamaya devam edin.
Sipariş tutarı, string olarak. Bu endpoint yalnızca USD kabul eder, amount_atomic kabul etmez.
fee_on
merchant — komisyonu siz ödersiniz, müşteri 15.00 görür. customer — komisyonu müşteri öder.
Idempotency-Key
Zorunlu. Aynı anahtarla yapılan yeniden deneme aynı faturayı döndürür.
partner_ref
İsteğe bağlı. Entegrasyonunuzu kuran entegratörün Partner ID'si (SnapEX Pay referans programı). Hesabınızı bu iş ortağına bir kez bağlar; entegrasyonu kendiniz yapıyorsanız bu alanı göndermeyin.
methods listesinden bir kod: usdt.trc20, usdt.erc20 veya usdt.bep20 (ödeme kendi adreslerimize gelir). Diğer ağlardaki USDT (usdt_solana, usdt_ton, …) ve diğer kripto paralar da aynı listeden gelir.
payment.address
Yalnızca bu adresi ve tutarı gösterin. Memo ve Tag kullanılmaz.
Eksik ödeme faturayı kapatmaz: durum underpaid olur ve aynı adres kalan tutarı bekler (USDT için 72 saat). Kalan tutar zamanında gelmezse fatura partially_paid durumuyla kapanır.
Not
Müşteriye gösterilen arayüzde dahili rotaların adını vermeyin. Ödeme sayfası yalnızca adresi, tutarı ve ağı gösterir.
İade API'si yoktur. Tamamlanan ikinci transfer ayrı bir bakiye eklemesidir, ilkinin geri alınması değildir.
İş kuralına bağlı ret. Yanıt yapısı (zarf) doğrulama hatalarındakiyle aynıdır.
details.amount
Hata bir alana bağlıdır ve formda gösterilebilir.
yanıt
{
"error": {
"code": "validation_error",
"message": "The request is invalid.",
"details": {
"amount": ["Yetersiz bakiye."]
// ← ret nedeni amount alanına bağlı
}
}
}
Hiçbir tutar bloke edilmez. Aynı Idempotency-Key ile yeniden denemek güvenlidir; önce bakiyenize para yatırın.
Not
held değerini hesaba katın: paranın bir kısmı başka bir çekim için bloke edildiyse available beklediğinizden düşük olur.
İşlemler
Ödeme geçmişi
Ledger bir işlem defteridir: bakiyeye eklenen, bakiyeden düşülen ve bloke edilen tutarlar ayrı kayıtlar olarak tutulur.
1
Geçmişi sayfa sayfa alın
Kayıtlar en yeniden en eskiye doğru döner. İstek başına en fazla 100 kayıt gelir; sonraki sayfa cursor ile alınır.
Önceki yanıttaki meta.next_cursor değeri. Rastgele bir değer kabul edilmez.
yanıt
{
"data": [ /* daha fazla kayıt var */ ],
"meta": {
"next_cursor": null, // ← son sayfa
"per_page": 50
}
}
Not
direction değeri reserve ve release olan kayıtlar, dışarı giden bir transfer değil, tutarın bloke edilmesi ve blokenin kaldırılmasıdır. Bunları harcama saymayın.
Yanıt gelmedi: aynı isteği tekrarlayın
1
Aynı isteği tekrarlayın
Aynı Idempotency-Key ve aynı parametreleri kullanın. Sunucu bunu aynı işlem olarak değerlendirir.
Bu yeni bir çekimse yeni bir Idempotency-Key kullanın.
yanıt
{
"error": {
"code": "conflict",
"message": "Idempotency-Key was used with different parameters."
}
}
Not
Anahtarı bir kez oluşturun ve siparişle birlikte saklayın. Her istekten önce yeni anahtar üretirseniz mükerrer işlem koruması devre dışı kalır.
HTTP 429 alırsanız birkaç saniye sonra aynı anahtarla yeniden deneyin.
Webhook'lar
Bir fatura, yatırma, çekim, dönüşüm veya bakiye değiştiğinde SnapEX, URL'nize bir POST isteği gönderir. Webhook bir sinyaldir, doğruluk kaynağı değildir: imzayı doğrulayın ve önemli kararlar için nesneyi API üzerinden yeniden okuyun.
Kurulum
URL'yi panelde ayarlayın
Panel → Geliştiriciler → “Webhook” kartı: URL'yi girin ve “Kaydet” düğmesine basın. Her hesap için tek bir URL vardır; aşağıdaki tablodaki tüm olay türleri bu adrese gönderilir.
İmza anahtarını saklayın
İlk kaydetmede panel whsec_… gizli anahtarını yalnızca bir kez gösterir. Anahtarı yalnızca kendi sunucunuzda tutun. URL'yi sonradan değiştirmek anahtarı değiştirmez.
URL gereksinimleri
Herkese açık bir host içeren mutlak bir https:// URL'si: URL'de login:password olmamalı, localhost kullanılmamalı ve host özel ya da ayrılmış bir IP adresine çözümlenmemelidir. URL, kaydedilirken ve her gönderim denemesinden önce yeniden kontrol edilir.
Ne gelir
Header
Anlamı
Webhook-Id
Benzersiz olay kimliği (UUID), gövdedeki id ile aynıdır. Yeniden denemelerde ve elle yeniden gönderimlerde değişmez — tekrarları bu değere göre ayıklayın.
Webhook-Timestamp
Bu denemenin gönderildiği an, saniye cinsinden Unix zamanı. Her yeniden denemede yeni bir değer ve yeni bir imza gelir.
Webhook-Signature
v1= ve ardından “{Webhook-Timestamp}.{ham gövde}” string'inin küçük harfli hex HMAC-SHA256 değeri. Anahtar, whsec_ öneki dahil gizli anahtarın tamamıdır.
Bakiyeye bir kayıt işlendi: ekleme, bloke veya düşüm.
Siparişi yalnızca invoice.paid geldiğinde teslim edin — bu olay yalnızca tutarın tamamı ödendiğinde gönderilir. invoice.underpaid ve invoice.partially_paid tutarın eksik olduğu anlamına gelir.
environment=test ile oluşturulan faturalar simüle edilir: aynı durumlardan geçer ve aynı webhook'ları gönderir (data.environment = "test"), ancak gerçek bakiyeyi asla değiştirmez.
Gönderim ve yeniden denemeler
Herhangi bir 2xx yanıtı başarılı sayılır. Diğer tüm kodlar, zaman aşımı veya ağ hatası başarısızlıktır. Yanıt gövdesi yorumlanmaz.
Zaman aşımları: bağlantı için 5 sn, isteğin tamamı için 15 sn.
Yönlendirmeler izlenmez: 301/302 başarısızlık sayılır. Nihai URL'yi girin.
Her olay için en fazla 5 deneme: ilk gönderim, ardından her başarısızlıktan sonra yaklaşık 10 sn, 1 dk, 5 dk ve 15 dk sonra yeniden deneme. Beşinci başarısızlıktan sonra otomatik gönderim durur.
Aynı sayfadaki “Webhook gönderimleri” kartında olay, HTTP kodu veya hata, zaman ve deneme numarası listelenir. “Yeniden gönder” düğmesi olayı aynı Webhook-Id ile tekrar gönderir.
Gönderim en az bir kez (at-least-once) ilkesiyle yapılır: aynı olay birkaç kez gelebilir ve olaylar sırasız gelebilir (yeniden denenen bir olay daha yeni bir olaydan sonra ulaşabilir).
İmza doğrulaması
İsteğin ham gövdesini JSON ayrıştırmasından önce bayt olarak okuyun. Yeniden serileştirilmiş JSON imzayla eşleşmez.
“{Webhook-Timestamp}.{ham gövde}” üzerinden, anahtar olarak whsec_… gizli anahtarınızla HMAC-SHA256 hesaplayın ve hex olarak kodlayın.
“v1=” + hex değerini Webhook-Signature header'ı ile sabit zamanlı bir fonksiyonla karşılaştırın: hash_equals, crypto.timingSafeEqual, hmac.compare_digest.
Saatinizden 5 dakikadan fazla farklı olan Webhook-Timestamp değerlerini reddedin (önerilir). Yeniden denemeler yeni bir zaman damgasıyla gelir, bu yüzden bu kontrol onları bozmaz.
PHP
<?php
$secret = getenv('SNAPEX_WEBHOOK_SECRET'); // panelden alınan whsec_…
$body = file_get_contents('php://input'); // ham gövde, JSON ayrıştırmasından önce
$timestamp = $_SERVER['HTTP_WEBHOOK_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_WEBHOOK_SIGNATURE'] ?? '';
$expected = 'v1='.hash_hmac('sha256', $timestamp.'.'.$body, $secret);
if (! ctype_digit($timestamp)
|| abs(time() - (int) $timestamp) > 300
|| ! hash_equals($expected, $signature)) {
http_response_code(400);
exit;
}
$event = json_decode($body, true);
// bu Webhook-Id zaten işlendiyse atlayın; ağır işleri kuyrukta yapın
http_response_code(200);
Müşteriye pay_url verin veya asset_id değerini kendiniz seçin
awaiting
Adres verildi, transfer bekleniyor
Adresi ve tutarı gösterin; durumu sorgulayın
underpaid
Tutarın bir kısmı geldi; adres aynı
Müşteriden kalan tutarı bu adrese göndermesini isteyin
paid
İlk tam transfer bakiyeye eklendi
Siparişi kapatın
nihai
partially_paid
Müşteri tutarın yalnızca bir kısmını ödedi, tamamlama süresi doldu, gelen kısım bakiyenize eklendi
Ödenmiş sipariş gibi teslim etmeyin; kalan tutarı müşteriyle çözün
nihai
expired
Fatura süresi doldu
Yeni bir fatura oluşturun
nihai
Çekimler
Durum
Anlamı
Ne yapmalı
reserved
Çekim için tutar bloke edildi
Bekleyin
submitting
Sağlayıcıya iletildi
Bekleyin
processing
Sağlayıcı zincir üzerinde gönderiyor
Bekleyin
completed
Tutar alıcıya ulaştı
Tamamlandı
nihai
manual_review
Sonuç belirsiz
Yeni bir çekim oluşturmayın; incelemeyi bekleyin
failed
Transfer başarısız oldu; bloke genellikle kaldırılır
Bakiyeyi kontrol edin; gerekirse yeni bir Idempotency-Key ile yeniden deneyin
nihai
Hatalar
Başarılı yanıt her zaman data içinde, hata her zaman error içinde gelir. Başka bir zarf yapısı yoktur.
hata yapısı
{
"error": {
"code": "validation_error", // makine tarafından okunabilir kod, aşağıdaki tabloya bakın
"message": "The request is invalid.",
"details": { // her zaman bulunmaz
"destination_address": ["The destination address field is required."]
// anahtar, doğrulamayı geçemeyen alandır
}
}
}
HTTP
code
Ne zaman
Ne yapmalı
401
unauthorized
Anahtar yok veya geçersiz
Authorization: Bearer smk_… header'ını boşluk ve satır sonu olmadan, eksiksiz kontrol edin
401
key_inactive
Anahtar iptal edildi
Önceki anahtar iptal edildi. Paneldeki güncel anahtarı kullanın
401
key_expired
Anahtarın süresi doldu
Yeni bir anahtar oluşturun
404
not_found
Id bulunamadı veya başka bir üye işyerine ait
Kendi yanıtınızdaki payment_id veya payout_id değerini kullanın
409
conflict
Idempotency-Key başka bir işleme bağlı ya da external_id zaten kullanılmış
Yeni bir işlem için yeni bir anahtar kullanın. Yeniden deneme için aynı anahtarı ve aynı parametreleri kullanın
422
validation_error
Geçersiz alanlar, süresi dolmuş credit-preview, yetersiz bakiye veya eksik Idempotency-Key
Hatalı alan ve neden details içinde yer alır
429
rate_limited
İstek limiti aşıldı
Daha sonra aynı Idempotency-Key ile yeniden deneyin
500
internal_error
Sunucu iç hatası
Daha sonra aynı Idempotency-Key ile yeniden deneyin. Sorun devam ederse destekle iletişime geçin ve X-Request-Id değerini ekleyin