Webhook Yeniden Deneme ve İdempotent İşleme Rehberi
Webhook yeniden deneme takvimi, 10 saniye kuralı, tekrarlanan olayları eleme ve kaçan bildirimler için mutabakat. Kripto ödeme webhook'larını sağlam işleyin.

Webhook yeniden deneme mekanizması, sunucunuz geçici olarak erişilemez olduğunda bile hiçbir ödeme bildiriminin kaybolmamasını sağlar. Ama bunun bir bedeli vardır: aynı olay size birden fazla kez ulaşabilir. Bu yazıda MercanPay'in webhook'ları ne zaman ve kaç kez yeniden denediğini, tekrarlanan olayları idempotent biçimde nasıl işleyeceğinizi ve bir bildirim kaçarsa mutabakatı nasıl yapacağınızı anlatıyoruz.
İmza doğrulamayı burada tekrar etmiyoruz. O konu için webhook imzası doğrulama rehberimize bakın. Olay türlerinin tam listesi de webhook olay türleri yazımızda.
Bir webhook ne zaman "teslim edildi" sayılır?
MercanPay, webhook URL'nize imzalı bir POST isteği gönderir. Teslimatın başarılı sayılması için sunucunuzun:
- 10 saniye içinde yanıt vermesi,
- 2xx bir HTTP kodu (örneğin
200) dönmesi
gerekir. Zaman aşımı, bağlantı hatası ya da 2xx dışındaki her yanıt (400, 401, 500, 502…) başarısız deneme sayılır.
Yeniden deneme takvimi
Başarısız bir denemeden sonra istek artan aralıklarla tekrarlanır:
| Deneme | Önceki denemeden sonra bekleme |
|---|---|
| 2 | 30 saniye |
| 3 | 2 dakika |
| 4 | 10 dakika |
| 5 | 30 dakika |
| 6 | 1 saat |
| 7 | 3 saat |
| 8 | 6 saat |
| 9 | 12 saat |
| 10 | 24 saat |
Son deneme de başarısız olursa teslimat başarısız olarak işaretlenir. Toplamda iki günü aşan bu pencere, sunucunuzdaki bakım ya da kısa kesintilerin bildirim kaybına dönüşmesini engeller.
Olay yalnızca durum gerçekten değiştiyse gönderilir
MercanPay webhook olaylarını, olaya neden olan durum değişikliğiyle aynı veritabanı işleminde kayda alır. Buna "transactional outbox" denir. Pratik sonucu şudur: size bir invoice.paid olayı geldiyse fatura gerçekten ödendi olarak kaydedilmiştir. Kaydedilmemiş bir değişiklik için olay gönderilmez.
Bu, sizin tarafınızda da aynı disiplini uygulamanız için iyi bir örnektir: siparişi "ödendi" yapma işlemini ve "bu olayı işledim" kaydını tek bir veritabanı işleminde yapın.
Aynı olay neden birden fazla gelir?
Yeniden deneme sistemi "en az bir kez" teslimat garanti eder, "tam olarak bir kez" değil. Tekrar şu durumlarda yaşanabilir:
- Sunucunuz siparişi işledi, ama yanıtı 10 saniyeden geç verdi. MercanPay bunu başarısız sayar ve yeniden dener.
- Yanıtınız ağda kayboldu.
- Paneldeki teslimat geçmişinden bir olayı elle yeniden gönderdiniz.
- Faturada
callback_urlverdiniz. Olay hem Ayarlar'daki Webhook URL'ye hem decallback_url'ye gider. İki adres aynı sisteme bakıyorsa aynı olayı iki kez görürsünüz.
Son maddede önemli bir ayrıntı var: her iki adrese giden istek aynı olay kimliğini (id) taşır. Bu yüzden olay kimliğiyle yapılan tekrar eleme, iki adres durumunda da doğru çalışır.
İdempotent işleme: adım adım
1. Olay kimliğini benzersiz olarak kaydedin
Her webhook gövdesinde bir id alanı vardır. Bunu UNIQUE kısıtlı bir tabloya yazın. Ekleme başarısızsa olay daha önce işlenmiştir.
CREATE TABLE processed_events (
event_id TEXT PRIMARY KEY,
received_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
2. Sipariş güncellemesini koşullu yapın
Olay kimliğine ek olarak siparişin durumunu da kontrol edin: "yalnızca henüz ödenmemişse ödendi yap". Bu ikinci kilit, farklı olay kimlikleri taşıyan ama aynı siparişi etkileyen olaylara karşı sizi korur. Örneğin önce invoice.partial, sonra invoice.paid gelmesi gibi.
3. Hızlı yanıt verin, ağır işi kuyruğa atın
E-posta göndermek, lisans üretmek ya da harici bir API'yi çağırmak 10 saniyeyi aşabilir. Webhook işleyicinizde yalnızca imzayı doğrulayın, olayı kaydedin, işi bir kuyruğa bırakın ve 200 dönün.
import json
import os
from flask import Flask, abort, request
from mercanpay import verify_webhook
app = Flask(__name__)
SECRET = os.environ["MERCANPAY_WEBHOOK_SECRET"]
@app.post("/mercanpay/webhook")
def webhook():
body = request.get_data()
if not verify_webhook(SECRET, body, request.headers.get("X-MercanPay-Signature", "")):
abort(401)
event = json.loads(body)
with db.transaction() as tx:
# event_id PRIMARY KEY: ikinci kez gelirse hiçbir şey eklenmez
inserted = tx.execute(
"INSERT INTO processed_events (event_id) VALUES (%s) ON CONFLICT DO NOTHING",
(event["id"],),
).rowcount
if inserted:
tx.execute(
"INSERT INTO jobs (kind, payload) VALUES (%s, %s)",
(event["type"], json.dumps(event["data"])),
)
return "", 200 # ağır iş arka plandaki işçide
Burada db ve jobs kendi uygulamanıza ait örnek yapılardır. Önemli olan desendir: doğrula, kaydet, kuyruğa bırak, hızlı yanıtla.
4. İş mantığında tutarı ve coini kontrol edin
Arka plandaki işçi, siparişi onaylamadan önce data.invoice.order_id, token ve paid_amount değerlerinin sizin kaydınızla eşleştiğini doğrulamalıdır. Sipariş numarası eşleştirmesini order_id ile fatura sipariş eşleştirme yazımızda anlattık.
Kaçan bildirimler için mutabakat
Sunucunuz iki günden uzun süre erişilemez kaldıysa ya da bir hata yüzünden olayları yanlış işlediyseniz, API ile durumu kendiniz kontrol edebilirsiniz. Bu yaklaşım, periyodik bir mutabakat görevi olarak da çalıştırılabilir.
from mercanpay import MercanPay
zp = MercanPay("https://mercanpay.com", os.environ["MERCANPAY_API_KEY"])
before = None
while True:
page = zp.list_invoices(status="paid", limit=100, before=before)
for inv in page["data"]:
ensure_order_paid(inv["order_id"], inv["token"], inv["paid_amount"]) # idempotent
before = page.get("next_before")
if not before:
break
ensure_order_paid fonksiyonu webhook işleyicinizle aynı koşullu güncellemeyi kullanmalıdır. Böylece mutabakat ile webhook aynı siparişi iki kez işlemez. Fazla ödenmiş faturalar için aynı döngüyü status="overpaid" ile de çalıştırın.
Mutabakatı ne sıklıkla çalıştırmalısınız?
Bu, hacminize ve siparişlerin ne kadar zamana duyarlı olduğuna bağlıdır. Genel bir yaklaşım:
- Anında teslim edilen dijital ürünlerde webhook birincil kanaldır. Mutabakatı günde bir kez, gözden kaçan bir şey olmadığını doğrulamak için çalıştırmak çoğu zaman yeterlidir.
- Bir kesinti yaşadığınızda sunucunuz tekrar ayağa kalkar kalkmaz, kesinti süresini kapsayacak şekilde bir kez elle çalıştırın. Yeniden denemeler zaten gelecektir, ama beklemek zorunda kalmazsınız.
- Yeni bir entegrasyonu canlıya aldığınız ilk günlerde mutabakat sonuçlarını webhook kayıtlarınızla karşılaştırmak, işleyicinizdeki hataları erkenden ortaya çıkarır.
Mutabakat görevi herhangi bir sipariş için "ödendi ama bizde ödenmemiş görünüyor" durumu bulduysa bunu sessizce düzeltmekle yetinmeyin; bir günlük kaydı bırakın. Böyle bir fark, webhook işleyicinizde incelenmesi gereken bir sorun olduğuna işaret eder.
Panelde teslimat geçmişi
Panelde Webhooklar sayfasında gönderilen her olayı görebilirsiniz:
- Olay türü ve hedef URL
- Deneme sayısı ve durum (iletildi, bekliyor, başarısız)
- HTTP yanıt kodu, yanıt süresi ve varsa hata
Bir olayı buradan yeniden gönderebilir, "Test gönder" ile bir test.ping olayı yollayabilirsiniz. Teslimat geçmişini CSV, Excel ya da PDF olarak da dışa aktarabilirsiniz. Bkz. kripto ödeme raporları.
Sık yapılan hatalar
- Önce iş, sonra yanıt: E-posta gönderimini beklerken 10 saniyeyi aşmak, gereksiz tekrarlara yol açar.
- Hata durumunda 200 dönmek: İşleyemediğiniz bir olaya 200 dönerseniz yeniden deneme olmaz. Gerçekten işleyemediyseniz 5xx dönün.
- Tekrarları
order_idile değil hiçbir şeyle elememek: Aynı lisansın iki kez gönderilmesi en yaygın sonuçtur. - Yönlendirme yapan bir URL kullanmak: HTTP'den HTTPS'e ya da başka bir yola yönlendiren adresler 2xx sayılmaz. Webhook URL'si doğrudan işleyiciye işaret etmelidir.
Sık sorulan sorular
Başarısız olarak işaretlenmiş bir olayı yeniden alabilir miyim?
Evet. Panelde Webhooklar sayfasındaki teslimat geçmişinden olayı yeniden gönderebilirsiniz. Ayrıca API ile faturaların güncel durumunu her zaman sorgulayabilirsiniz.
Olaylar sırayla mı gelir?
Sıraya güvenmeyin. Yeniden denemeler nedeniyle olaylar farklı sırada ulaşabilir. İş mantığınızı fatura durumuna göre kurun.
Olay kimliği mi, order_id mi ile tekrar elemeliyim?
İkisini birlikte kullanın. Olay kimliği aynı olayın tekrarını, sipariş durumu kontrolü ise aynı siparişi etkileyen farklı olayları yakalar.
MercanPay ile başlayın
Kaybolmayan, imzalı ve yeniden denenen webhook'larla kripto ödeme almak için satıcı başvurunuzu yapın. Tüm ayrıntılar dokümantasyonda.


