PayTR Python Client
PayTR API entegrasyonu için hafif, tamamen asenkron ve framework bağımsız bir Python kütüphanesi. Tek bağımlılığı aiohttp'dir; FastAPI, Django, Flask veya düz script'lerle aynı şekilde çalışır.
Desteklenen Özellikler
| Özellik | PayTR Endpoint'i | İstemci Metodu |
|---|---|---|
| iFrame Token (1. Adım — yeni tasarım v2, Kart & Havale/EFT) | /odeme/api/get-token |
create_iframe_token() |
| Bildirim (Callback) (2. Adım — iFrame, EFT, Direct, Link) | Sizin Bildirim URL'niz | handle_callback() / parse_callback() |
| İade (Tam veya Kısmi) | /odeme/iade |
refund() |
| Durum Sorgulama | /odeme/durum-sorgu |
status() |
| İşlem Dökümü / Ödeme Özeti / Ödeme Detayı | /rapor/... |
transaction_detail() / payment_statement() / payment_detail() |
| Ödeme Linki (Oluşturma & Silme) | /odeme/api/link/... |
create_payment_link() / delete_payment_link() |
| BIN & Taksit Oranları | /odeme/api/bin-detail, /odeme/taksit-oranlari |
bin_detail() / installment_rates() |
| Kayıtlı Kartlar (Listeleme & Silme) | /odeme/capi/... |
list_cards() / delete_card() |
| Tekrarlayan Ödeme (Kayıtlı karttan, Non3D) | /odeme |
recurring_payment() |
Bildirim dışındaki tüm işlemler yetki gerektirir: bunları yalnızca kendi yetkilendirilmiş backend kodunuzdan çağırın, asla doğrudan dışarıya açmayın.
📦 Kurulum
pip install paytr-python
# VEYA
uv add paytr-python
merchant_id, merchant_key ve merchant_salt değerleri PayTR Mağaza Paneli > Destek & Kurulum > Entegrasyon Bilgileri sayfasındadır.
🚀 Kullanım
from paytr import PayTRClient, get_client_ip
client = PayTRClient.from_env() # PAYTR_MERCHANT_ID / _KEY / _SALT (+ _TEST_MODE=1, _DEBUG_ON=1)
# veya: PayTRClient(merchant_id="...", merchant_key="...", merchant_salt="...")
1. Adım — Ödeme başlatma (kendi yetkilendirilmiş endpoint'inizde)
Tutarı ve sepeti sunucunuzda, kendi fiyatlarınızdan hesaplayın; istemciden gelen fiyata asla güvenmeyin.
result = await client.create_iframe_token(
merchant_oid="SIPARIS123", # Alfanümerik, en fazla 64 karakter
email="alici@example.com", # En fazla 100 karakter, Türkçe karakter olmadan
payment_amount="34.56", # TL (str, float veya Decimal), en az 1.00
user_ip=get_client_ip(request.headers, request.client.host),
user_basket=[("Ürün 1", "18.00", 1), ("Ürün 2", "16.56", 1)], # (isim, birim fiyat, adet)
merchant_ok_url="https://siteniz.com/basarili",
merchant_fail_url="https://siteniz.com/hata",
user_name="Ayşe Yılmaz", user_address="İstanbul", user_phone="05551112233",
# Opsiyonel: no_installment=True, max_installment=6, timeout_limit=30 (dk),
# dark_mode=True, payment_type="eft", lang="en", test_mode=True (sadece bu istek için)
)
result["iframe_url"] # kart veya Havale/EFT için doğru adres
Sayfanıza gömmek için paytr.iframe_html(token) hazır HTML verir (yeni tasarımın ?v2 script'i ile). iFrame'in id'si paytriframe olmalıdır: PayTR'nin script'i bu id'yi sabit kullanır.
2. Adım — Bildirim (callback)
PayTR sonucu panelde tanımladığınız Bildirim URL'ye POST eder. handle_callback imzayı doğrular, işleyicinizi çalıştırır ve PayTR'ye dönmeniz gereken yanıtı verir — herhangi bir framework'te:
from paytr import Callback
async def on_payment(data: Callback) -> bool | None:
# Yalnızca imzası doğrulanmış bildirimler gelir. PayTR aynı bildirimi tekrar
# gönderebilir: her merchant_oid'i yalnızca BİR KEZ işleyin (idempotent).
if data.is_test and not expecting_test_orders:
return # test ödemesi gerçek siparişi onaylamasın
if data.is_success:
... # data.paid_minor_units'i siparişin beklenen tutarıyla (kuruş) karşılaştırın
# False dönmek (veya exception) PayTR'nin bildirimi tekrar göndermesini sağlar.
# FastAPI
@app.post("/paytr/callback")
async def paytr_callback(request: Request):
body, status = await client.handle_callback(await request.form(), on_payment)
return PlainTextResponse(body, status_code=status)
| Durum | Yanıt |
|---|---|
| Geçersiz / eksik imza | 400 — on_payment çağrılmaz |
on_payment exception fırlatır veya False döner |
500 — PayTR ~1 dk sonra tekrar dener |
| Diğer | 200 OK — PayTR durur |
Kendi akışınızı kurmak isterseniz client.parse_callback(form) doğrulanmış bir Callback döner (geçersizse PayTRSignatureError). Callback alanları: merchant_oid, status, total_amount (kuruş), is_success, is_test, paid_minor_units, failed_reason_code, error_message ve diğer tüm alanlar için raw.
Diğer Backend Metotları
# İade (TL). Her iadeye bir reference_no atanır; ağ hatasında iadenin PayTR'de
# kaydedilip kaydedilmediği status() ile kontrol edilir — körlemesine tekrar
# deneyip çift iade yapılmaz.
await client.refund(merchant_oid="SIPARIS123", return_amount="11.90")
await client.status("SIPARIS123") # tutar, iadeler (returns), kart bilgisi…
# Raporlar PayTR'nin ham yanıtını döner (veri yoksa {}).
await client.transaction_detail(start_date="2026-06-01 00:00:00", end_date="2026-06-03 23:59:59") # en fazla 3 gün; dummy=True örnek veri
await client.payment_statement(start_date="2026-06-01", end_date="2026-06-30")
await client.payment_detail("2026-06-05")
link = await client.create_payment_link(name="Özel Tişört", price=14.45, min_count=1)
await client.delete_payment_link(link["id"])
# callback_link verirseniz callback_id zorunludur; bildirimi handle_callback doğrular.
await client.bin_detail("435508")
await client.installment_rates("req123")
cards = await client.list_cards("kullanici_tokeni") # Non3D yetkisi gerekir
await client.recurring_payment(
utoken="kullanici_tokeni", ctoken=cards[0]["ctoken"],
merchant_oid="SIPARIS124", email="alici@example.com", payment_amount="34.56",
user_ip="1.2.3.4", user_name="Ayşe", user_address="İstanbul", user_phone="0555...",
user_basket=[("Ürün 1", "34.56", 1)],
merchant_ok_url="https://siteniz.com/ok", merchant_fail_url="https://siteniz.com/fail",
)
❌ Hata Yönetimi
| Exception | Ne zaman |
|---|---|
PayTRConfigError |
Eksik kimlik bilgisi veya PayTR'nin reddedeceği girdi (hatalı merchant_oid, e-posta, IP, 1 TL altı tutar, boş sepet) — istek hiç gönderilmez |
PayTRNetworkError |
Bağlantı hatası, zaman aşımı, geçersiz yanıt |
PayTRSignatureError |
Bildirimde eksik alan veya geçersiz imza |
PayTRAPIError |
PayTR hata döndü: .message, .code (err_no), .payload (ham yanıt) |
Hepsi PayTRError'dan türer. Hata kodlarını açıklamaya çevirmek için: describe("payment", "10"), describe("refund", "009").
📝 Loglama
Kütüphane varsayılan olarak sessizdir. Logları görmek için tek satır yeterli:
import paytr
paytr.enable_logging() # veya enable_logging("DEBUG")
[PAYTR] INFO: callback oid=SIPARIS123 status=success total=3456 test=False
[PAYTR] WARNING: callback rejected: bad hash
Uygulamanız logging'i zaten kendisi yapılandırıyorsa (basicConfig, Sentry vb.) enable_logging çağırmayın; kütüphane standart "paytr" logger'ına (paytr.logger) yazdığı için loglar sizin yapılandırmanıza akar.
| Seviye | Olay |
|---|---|
DEBUG |
Her PayTR isteği (URL) |
INFO |
Doğrulanmış bildirim (oid, durum, tutar, test) |
WARNING |
Reddedilen bildirim, PayTR API hatası, IPv6 user_ip, ağ hatası sonrası doğrulanan iade |
ERROR |
Ağ hatası, on_payment exception'ı (stack trace ile) |
🔄 HTTP Oturumu
Varsayılan olarak ilk istekte 30 sn timeout'lu bir aiohttp.ClientSession açılır (timeout=10 ile değiştirilebilir). Kendi oturumunuzu da verebilirsiniz: PayTRClient(..., session=my_aiohttp_session) — dışarıdan verilen oturum kütüphane tarafından kapatılmaz. Uygulama kapanırken await client.aclose() çağırın veya async with PayTRClient(...) as client: kullanın.
🕹️ Demo Uygulama
src/ altında FastAPI ile küçük bir demo var: api/payment.py callback rotası ve yalnızca test modunda çalışan bir /pay rotası içerir (tarayıcıdan gelen fiyata güvendiği için canlı modda reddeder).
uv sync
cp src/example.env .env # PayTR bilgilerinizi girin, PAYTR_TEST_MODE=1
cd src && uv run main.py # http://127.0.0.1:8000/paytr/
uv run pytest # ağ bağlantısı gerektirmez
🧪 Test Kartları
test_mode açıkken: Visa 4355084355084358, Mastercard 5406675406675403, Troy 9792030394440796 — son kullanma 12/30, CVV 000. iFrame'de test kartı otomatik doldurulur.
Release files for paytr-python 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| paytr_python-0.3.0.tar.gz | 28.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| paytr_python-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 53.2 kB
Release files / paytr_python-0.3.0.tar.gz
| Download URL | paytr_python-0.3.0.tar.gz |
|---|---|
| Size | 28.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2d0784660dd35ddfe5dc5f09cfb511481d195ee28cf176eadf1347fa697b42a2
|
|
BLAKE2b-256 checksum How to use checksums |
7ac524d76df43d0b94f1c988bc74e5f2c65f4b3bc592c9dccdad01311869ac49
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.
Transparency logRelease files / paytr_python-0.3.0-py3-none-any.whl
| Download URL | paytr_python-0.3.0-py3-none-any.whl |
|---|---|
| Size | 24.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4e71da49b2b4b9046a48a0842370180584432250dd64c90ae3961fed799db5a3
|
|
BLAKE2b-256 checksum How to use checksums |
557e62efcf8a11ffcf3ff1c8ebeb16a6f4e95d680378383db8d08c7bf876a7ba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.
Transparency log