Python ile Kripto Ödeme Entegrasyonu: Flask ve Django Örneği
Python ile kripto ödeme entegrasyonu: pip install mercanpay ile USDT/TRX faturası oluşturma, webhook doğrulama ve sipariş onayını Flask ve Django ile öğrenin.

Python ile kripto ödeme entegrasyonu, resmi mercanpay paketi sayesinde birkaç satırlık bir iştir. Siparişte bir fatura açar, müşteriyi ödeme sayfasına yönlendirir, imzalı webhook ile de siparişi onaylarsınız. Bu rehberde USDT ve TRX (TRC20) ödemelerini Flask ve Django uygulamalarına adım adım bağlıyoruz.
Gereksinimler
- Python 3 ve
pip - Onaylı bir MercanPay satıcı hesabı (başvuru)
- Panelden oluşturulmuş,
invoicesyetkili bir API anahtarı - Ayarlar sayfasındaki webhook imza sırrı (
whsec_...)
1. Paketi kurun
pip install mercanpay
Paket yalnızca requests kütüphanesine dayanır. Gizli bilgileri ortam değişkenlerinde tutun:
export MERCANPAY_API_KEY="mp_..."
export MERCANPAY_WEBHOOK_SECRET="whsec_..."
2. İstemciyi oluşturun
import os
from mercanpay import MercanPay, MercanPayError, verify_webhook
zp = MercanPay("https://mercanpay.com", os.environ["MERCANPAY_API_KEY"])
İstemci varsayılan olarak 15 saniyelik zaman aşımı kullanır. Gerekirse MercanPay(base_url, api_key, timeout=10) ile değiştirebilirsiniz.
3. Python ile kripto ödeme faturası oluşturun
create_invoice metodu iki kullanım biçimini destekler:
# USD fiyatlı: müşteri ödeme sayfasında TRX veya USDT seçer, kur kilitlenir
inv = zp.create_invoice(
price_usd="49.90",
order_id="order-1001",
description="Pro lisans (1 yıl)",
success_url="https://magazam.com/siparis/1001/tesekkurler",
return_url="https://magazam.com/sepet",
metadata={"customer_id": 42},
)
# Sabit coin: tam olarak 49.90 USDT
inv = zp.create_invoice("USDT", "49.90", order_id="order-1002")
print(inv["status"], inv["address"], inv["payment_url"])
Coin seçeneklerini sınırlamak için tokens=["USDT"], faturanın süresini belirlemek için expires_in_minutes (5–1440) kullanabilirsiniz.
Unutmamanız gereken kurallar:
- Tutarlar metin olarak gönderilir:
"49.90". Float kullanmayın. order_idtekrar denemeye karşı güvenlidir: Aynı değerle ikinci çağrı yeni fatura açmaz, mevcut faturayı döndürür.- Minimum fatura tutarı 10 $'dır. USDT faturalarına, müşterinin ödediği 1 USDT ağ ücreti eklenir.
- Faturalar en fazla 24 saat açık kalır.
4. Flask ile uçtan uca örnek
import json
import os
from flask import Flask, abort, redirect, request
from mercanpay import MercanPay, MercanPayError, verify_webhook
app = Flask(__name__)
zp = MercanPay("https://mercanpay.com", os.environ["MERCANPAY_API_KEY"])
SECRET = os.environ["MERCANPAY_WEBHOOK_SECRET"]
@app.post("/checkout/<order_id>")
def checkout(order_id):
order = load_order(order_id) # kendi veritabanı fonksiyonunuz
try:
inv = zp.create_invoice(
price_usd=order.total_usd, # ör. "49.90"
order_id=order.id,
callback_url="https://magazam.com/mercanpay/webhook",
success_url=f"https://magazam.com/siparis/{order.id}/tesekkurler",
)
except MercanPayError as e:
app.logger.error("MercanPay %s %s", e.code, e.message)
abort(502)
return redirect(inv["payment_url"])
@app.post("/mercanpay/webhook")
def webhook():
raw = request.get_data() # ham gövde, imza bunun üzerinden hesaplanır
header = request.headers.get("X-MercanPay-Signature", "")
if not verify_webhook(SECRET, raw, header):
abort(401)
event = json.loads(raw)
invoice = event["data"].get("invoice") or {}
if event["type"] in ("invoice.paid", "invoice.overpaid"):
fulfil_once(event["id"], invoice["order_id"], invoice["token"], invoice["paid_amount"])
elif event["type"] == "invoice.partial":
notify_customer_remaining(invoice["order_id"])
elif event["type"] in ("invoice.expired", "invoice.cancelled"):
release_stock(invoice["order_id"])
return "", 200
verify_webhook, X-MercanPay-Signature başlığındaki t=<unix>,v1=<hex> değerini ayrıştırır. Zaman damgası 5 dakikadan eskiyse isteği reddeder, imzayı hmac.compare_digest ile sabit zamanlı karşılaştırır. Mekanizmanın ayrıntıları webhook imzası doğrulama yazısında.
İmza ham gövde üzerinden hesaplanır.
request.get_json()ile ayrıştırıp yeniden serileştirdiğiniz veriyle doğrulama yapmayın, baytlar değişebilir.
Tekrarlanan olaylara dikkat
Sunucunuz 10 saniye içinde 2xx dönmezse webhook artan aralıklarla tekrar gönderilir. Bu yüzden aynı olay size birden fazla kez ulaşabilir. fulfil_once fonksiyonunuz olay kimliğini (event["id"]) benzersiz bir sütuna kaydetmeli ve daha önce işlenmiş olayları atlamalıdır. Ağır işleri (e-posta, fatura PDF'i vb.) bir iş kuyruğuna bırakıp hızlıca 200 dönün.
5. Django ile webhook
import json
import os
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from mercanpay import verify_webhook
@csrf_exempt
@require_POST
def mercanpay_webhook(request):
header = request.headers.get("X-MercanPay-Signature", "")
if not verify_webhook(os.environ["MERCANPAY_WEBHOOK_SECRET"], request.body, header):
return HttpResponse(status=401)
event = json.loads(request.body)
if event["type"] in ("invoice.paid", "invoice.overpaid"):
fulfil_once(event["id"], event["data"]["invoice"]["order_id"])
return HttpResponse(status=200)
Webhook istekleri tarayıcıdan gelmediği için CSRF korumasını bu görünümde kapatmanız gerekir. Güvenliği imza doğrulaması sağlar.
6. Sorgulama ve mutabakat
Webhook'a ek olarak API'den de fatura durumunu okuyabilirsiniz. Başarılı sayfasında veya gece çalışan bir mutabakat görevinde işe yarar:
inv = zp.get_invoice_by_order("order-1001")
if inv["status"] in ("paid", "overpaid"):
...
page = zp.list_invoices(status="paid", limit=20)
for inv in page["data"]:
reconcile(inv)
next_page = zp.list_invoices(status="paid", limit=20, before=page["next_before"])
Güncel kurları görmek için zp.rates() kullanabilirsiniz. Örneğin {"TRX": "0.3342", "USDT": "1"} biçiminde bir sözlük döner.
USD fiyatı mı, sabit coin mi?
Entegrasyona başlamadan önce vermeniz gereken ilk karar, faturalarınızı nasıl fiyatlandıracağınızdır:
price_usd (USD fiyatlı) |
token + amount (sabit coin) |
|
|---|---|---|
| Müşteri deneyimi | Ödeme sayfasında TRX veya USDT seçer | Tek coin ile öder |
| Kur | Müşteri coin seçtiğinde kilitlenir | Kur hesabı yok, tutar sabit |
| Uygun olduğu durum | Mağaza fiyatları dolar cinsindense | Fiyatlarınız zaten USDT ise |
| Geç ödeme | USD fiyatlı TRX faturasında güncel kurdan yeniden fiyatlanır | Faturadaki tutar geçerlidir |
Dolar fiyatlı bir mağazada çoğu zaman price_usd en az sürtünmeli seçenektir. Müşteri elindeki coin ile ödeyebilir, siz de kur hesabıyla uğraşmazsınız. Kur riskini ve kur kilidinin nasıl çalıştığını kripto ödemede kur riski yazısında ayrıntılı ele aldık.
Canlıya geçmeden önce kontrol listesi
- API anahtarı yalnızca sunucuda, ortam değişkeninde duruyor. Kaynak koda veya ön yüze hiç girmiyor.
- Anahtara yalnızca ihtiyaç duyduğu yetkiler verilmiş. Fatura oluşturan bir web uygulamasının
withdrawalsyetkisine ihtiyacı yoktur. - Webhook URL HTTPS ve
verify_webhookher istekte çalışıyor. - Her siparişin benzersiz bir
order_iddeğeri var, tekrar denemeler çift fatura açmıyor. invoice.partial,invoice.overpaidveinvoice.expiredolayları ele alınıyor.- Sipariş,
success_urlyönlendirmesine değil webhook'a göre onaylanıyor. - Akış, küçük tutarlı gerçek bir ödemeyle uçtan uca denendi.
API anahtarlarının ve çekim adreslerinin güvenliği için kripto hesap güvenliği yazımıza da göz atabilirsiniz.
Hata yönetimi
API 2xx dışında bir yanıt verdiğinde MercanPayError fırlatılır:
| Özellik | Açıklama |
|---|---|
e.status |
HTTP kodu |
e.code |
Makine okunur kod, ör. validation_error, unauthorized, insufficient_funds |
e.message |
Açıklama |
429 ve 5xx hatalarında kısa bir beklemenin ardından aynı çağrıyı tekrarlayın. Hız sınırı varsayılan olarak IP başına dakikada 120 istektir.
Sık sorulan sorular
Asenkron (asyncio) bir uygulamada kullanabilir miyim?
İstemci senkron requests kullanır. Asenkron uygulamalarda çağrıyı bir thread havuzunda çalıştırabilir ya da REST API'yi kendi asenkron HTTP istemcinizle doğrudan çağırabilirsiniz.
Çekim yapabilir miyim?
Evet. withdrawals yetkili bir anahtarla zp.create_withdrawal("USDT", "50", "T...", idempotency_key="payout-001") çağrısını kullanabilirsiniz. Aynı idempotency_key ile tekrar deneme ikinci bir çekim oluşturmaz. API çekimleri yalnızca panelde güvenilir olarak işaretlenmiş adreslere yapılabilir.
Test için nasıl bir yol izlemeliyim?
Panelde Webhooklar sayfasındaki "Test gönder" ile bir test.ping olayı alabilirsiniz. Canlıya geçmeden önce akışı küçük tutarlı gerçek bir ödemeyle uçtan uca deneyin.
MercanPay ile başlayın
Python ile kripto ödeme entegrasyonu için tek bir pip install yeterli. PHP kullanıyorsanız PHP entegrasyon rehberimize göz atın. Satıcı hesabınızı oluşturun ve ilk USDT ödemenizi bugün alın.


