Türkiye’de ödeme entegrasyonları için iyzico ve PayTR iki popüler seçenek. 6 farklı WooCommerce sitesinde PayTR kurdum. Özellikleri, zorlukları, iyzico’dan farkı üzerine notlar.
PayTR neden seçiliyor
PayTR’nin öne çıkan farkları:
– Komisyon oranları bazı kart tipleri için iyzico’dan düşük
– Non-3D ve 3D Secure her ikisi de mevcut, daha esnek konfigürasyon
– iFrame-based checkout daha kolay entegrasyon
– Link with Pay ödeme linki (mesaj ile gönder, tıkla-ödeme) güçlü
– Taksit sistemi kart bazında granular
Dezavantajları:
– Dokümantasyon iyzico’ya göre daha karışık
– Test kartları az, test senaryoları sınırlı
– API response formatları tutarsız (bazı endpoint JSON, bazı form-encoded)
– Dashboard iyzico’dan daha az polish
İlk kurulum: merchant onboarding
PayTR merchant hesabı açmak 1-2 hafta sürüyor:
– Vergi levhası, faaliyet belgesi yükleme
– Banka hesap bilgisi doğrulama
– İşyeri inceleme
– Test hesap açıldıktan sonra test ortamında teknik entegrasyon
– Production geçişi için ek inceleme
Bu süreç başından sonuna developer’ın elinde değil. Müşterinin operation ekibi ile paralel yürütülüyor.
iFrame checkout: en basit entegrasyon
PayTR’nin iFrame API’si en hızlı yol:
- Backend’de
get_tokenendpoint’ine POST. Sipariş bilgisi + merchant credentials. - PayTR bir
tokendönüyor. - Frontend’de
https://www.paytr.com/odeme/guvenli/URL’i iframe’e embed ediliyor. - Kullanıcı iframe içinde kart bilgisi giriyor, 3D OTP giriyor.
- Sonuç PayTR’den callback URL’inize POST ediyor.
iFrame’in avantajı: kart bilgisi sizin sunucunuza hiç gelmiyor, PCI compliance yükü PayTR’de. En düşük güvenlik riski.
Dezavantajı: iFrame UI’ı PayTR branding’i ile geliyor. Custom UX çok sınırlı.
Hash hesabı: dikkat gerektiren yer
Her PayTR request’i hash ile imzalanıyor. Hash yanlış = request reject.
$merchant_id = 'XXXXXX';
$merchant_key = 'XXXXXXX';
$merchant_salt = 'XXXXXXX';
$hash_str = $merchant_id . $user_ip . $merchant_oid . $email . $payment_amount . $user_basket . $no_installment . $max_installment . $currency . $test_mode;
$paytr_token = base64_encode(hash_hmac('sha256', $hash_str . $merchant_salt, $merchant_key, true));Yaygın hatalar:
– $user_basket base64 encode edildikten sonra mı önce mi hash’e gidecek: base64’den sonra
– $payment_amount integer olmalı, ondalık değil (100 TL = 10000)
– $test_mode string ‘1’ veya ‘0’ olmalı, boolean değil
Hash hesabında 1 karakter farkla token invalid geliyor, debug saat alabiliyor. PayTR’nin PHP SDK’sını kullanın manuel yazmaktan kaçının.
Callback URL: kritik endpoint
PayTR ödeme sonucunu callback URL’inize POST ediyor. Handler:
add_action('init', function() {
if (!isset($_POST['merchant_oid'])) return;
$post = $_POST;
$hash_verify = base64_encode(hash_hmac(
'sha256',
$post['merchant_oid'] . $merchant_salt . $post['status'] . $post['total_amount'],
$merchant_key,
true
));
if ($hash_verify !== $post['hash']) {
echo 'PAYTR notification failed: bad hash';
exit;
}
if ($post['status'] === 'success') {
// Siparişi başarılı olarak işaretle
$order_id = get_order_by_oid($post['merchant_oid']);
$order = wc_get_order($order_id);
$order->payment_complete($post['merchant_oid']);
} else {
$order->update_status('failed', $post['failed_reason_msg']);
}
echo 'OK';
exit;
});Önemli:
– Hash verification ilk iş
– “OK” cevabı hemen dönüyor, yoksa PayTR retry yapıyor
– Order status sadece success durumunda tamamlanıyor
– failed_reason_code alanı debug için logla
Callback timing ve retry
PayTR callback’i immediate değil, ödeme tamamlandıktan 5-15 saniye sonra geliyor. Kullanıcı iframe’de “ödeme başarılı” gördüğü an callback henüz gelmemiş olabiliyor.
Bu nedenle:
– Frontend success page’inde “ödemeniz işleniyor, size e-posta göndereceğiz” mesajı
– Backend callback’e kadar siparişi pending’de tutun
– Kullanıcı success page’ini yenilerse order status güncellenmişse göstermelisiniz
Callback gelmezse PayTR 3 kez retry yapıyor (5, 15, 60 dakika). Hala başarısız ise manuel reconciliation gerekli.
Payment link: B2B için ideal
PayTR’nin “Payment Link” özelliği B2B siparişlerde güzel kullanım:
- Operations panel’den ödeme tutarı + email girilerek link oluşturuluyor
- Link WhatsApp / email ile müşteriye gönderiliyor
- Müşteri link’e tıklayıp ödüyor
- Tamamlanma notification’ı e-posta + callback ile geliyor
Bu akış ERP’li toptan satış siteleri için çok uygun. Checkout süreci olmadan da ödeme alınabiliyor.
Taksit: kart bazında granular
PayTR her kart bankası için farklı taksit seçeneği dönüyor:
- Yapı Kredi WorldPuan: 6 taksit opsiyonu
- Garanti BonusCard: 9 taksit
- İş Bankası Maximum: 3 taksit
BIN inquiry endpoint ile kart numarasının ilk 6 hanesinden hangi banka olduğunu çıkarıyorsunuz, o bankanın taksit opsiyonlarını gösteriyorsunuz.
Not: taksit komisyonu merchant’a kesiliyor, end user’a gösterilen fiyat değişmiyor. Taksit yapan kart sayısı yüksek ise komisyon önemli kalem olabilir.
Production go-live checklist
Test’ten production’a geçmeden önce:
- [ ] Production credentials alındı
- [ ] Config environment variable’lar güncellendi
- [ ]
test_mode: 0olarak set edildi - [ ] Callback URL production domain’inde çalışıyor
- [ ] SSL certificate geçerli (PayTR https olmayan callback’e POST yapmıyor)
- [ ] Order status transition’ları test edildi (success, failed, cancelled)
- [ ] Fraud reason code mapping yapıldı
- [ ] Müşteriye spesifik error mesajları
- [ ] Webhook signature verification aktif
- [ ] Refund flow test edildi (refund endpoint ayrı)
- [ ] Reporting + reconciliation job’ı kurulu
Bu 11 madde olmadan production’a geçince 2. haftada incident yaşıyorsunuz.
Hata mesajları
PayTR failed_reason_msg alanı Türkçe açıklama veriyor:
– “Geçersiz kart numarası”
– “Kart limiti yetersiz”
– “Provizyon alınamadı”
– “İşlem reddedildi, bankanızla görüşünüz”
Bu mesajları olduğu gibi kullanıcıya gösterebilirsiniz. iyzico’nun error code map’ine göre tercüme gerekmiyor.
Önemli: fraud reject’lerde detaylı mesaj vermeyin. “İşlem güvenlik kontrolüne takıldı, desteğe yazın” yeterli. Fraud pattern’ını açıklamak attacker’lara ipucu veriyor.
Son tavsiye
PayTR iyzico’ya kıyasla daha az polish ama bazı kartlarda daha iyi komisyon, Payment Link gibi özgün özellikler sunuyor. Tercih müşterinin volume, kart profili, dashboard kullanım tercihine göre değişiyor.
Ben müşteriye iyzico + PayTR’yi paralel kurmayı öneriyorum: checkout’ta kullanıcı seçebiliyor, biri outage yaşarsa diğeri devam ediyor, komisyon optimizasyonu için trafiği ölçerek dağıtılıyor. Daha sağlam setup.