Refactored the iyzico payment integration to improve the handling of payment callbacks and order status updates. Added signature validation for responses to ensure data integrity. Enhanced the `initializeCheckoutForm` function to include buyer's name and surname, and updated the order schema to enforce unique constraints on iyzico tokens. Improved error handling and logging for payment processing, ensuring better tracking of payment states and issues. Updated the app database to reflect these changes.
5.1 KiB
iyzico ödeme entegrasyonu
Ödeme akışı iyzico Checkout Form (CF) üzerinden yürür: kart bilgisi hiçbir zaman bize ulaşmaz, kullanıcı iyzico'nun barındırdığı ödeme sayfasına gider.
Ortam değişkenleri
| Değişken | Açıklama |
|---|---|
IYZICO_API_KEY |
Merchant Portal → Ayarlar → API anahtarları |
IYZICO_SECRET_KEY |
Aynı ekran. İmza doğrulamasında da kullanılır |
IYZICO_BASE_URL |
Sandbox: https://sandbox-api.iyzipay.com · Canlı: https://api.iyzipay.com |
NEXT_PUBLIC_APP_URL |
callback ve webhook URL'lerinin kökü; https ve geçerli SSL şart |
IYZICO_BASE_URL verilmezse sandbox'a düşülür. Prod'da bu durum log'a uyarı
basar — canlıya çıkarken bu satır mutlaka ayarlanmalı.
Lokal
http://localhost:3000ile uçtan uca test edilemez: iyzico callback adresinden geçerli SSL ister. Sandbox testinde tünel (cloudflared/ngrok) açıpNEXT_PUBLIC_APP_URL'i o https adrese ayarla.
Akış
baslatOdeme(src/features/odeme/odeme-actions.ts) —orderssatırınıpendingolarak yazar,checkoutFormInitializeçağırır, dönentoken'ı siparişe iliştirir ve kullanıcıyıpaymentPageUrl'e yönlendirir.conversationId=basketId= sipariş id'miz.- Kullanıcı ödemeyi bitirince iyzico
/api/odeme/callbackadresine cross-site POST atar; gövdede yalnızcatokenvardır. SameSite=Lax nedeniyle session çerezi gelmez, bu yüzden kullanıcı token'dan çözülür. odemeyiSonuclandir(src/lib/odeme.ts) iyzico'yacheckoutForm.retrieveile sorar ve krediyi idempotent tanımlar. Kullanıcı 303 ile/odeme/sonuc?siparis=…sayfasına düşer./odeme/sonucself-healing'dir: sipariş hâlâpendingise aynı fonksiyonu tekrar çağırır (callback kaybolduysa kurtarır)./api/odeme/webhookiyzico bildirimini karşılar — sekmesini kapatan ya da fraud incelemesinde bekleyen ödemeler için yedek yol.
Doğruluk kuralları (bunlara dokunurken dikkat)
- Kredi yalnızca
retrieveyanıtına göre tanımlanır. Ne callback gövdesine ne webhook gövdesine güvenilir; ikisi de sadece "iyzico'ya tekrar sor" tetikleyicisidir. paidgeçişi koşulludur (WHERE status != 'paid'): eşzamanlı callback + sayfa render'ı ikinci kez kredi yazamaz.grantCredits'tekiUNIQUE(reason, ref_id)ikinci katman güvencedir.- Ara durumlar
faileddamgalanmaz.INIT_THREEDS,CALLBACK_THREEDS,PENDING_CREDIT,INIT_BANK_TRANSFER… ödemenin sonuçlanmadığı anlamına gelir; damgalarsak dakikalar sonra SUCCESS'e dönen ödemede kredi kaybolur. fraudStatus:1onaylı → kredi verilir.0incelemede →pendingbırakılır (çekim kesinleşmemiştir).-1reddedildi →failed.- Erken
failedkurtarılabilir: geçiş koşulustatus != 'paid'olduğu için yanlışlıklafaileddamgalanmış bir sipariş, iyzico SUCCESS derse yinepaid'e döner. Para çekildiyse kredi mutlaka tanımlanır. - Tutar kontrolü:
paidPricesipariş tutarıyla eşleşmiyorsa kredi otomatik tanımlanmaz, log'a düşer.
İmza doğrulaması
iyzico yanıtlarında HMAC-SHA256 signature döner; alanlar : ile birleşir ve
fiyatlarda sondaki sıfırlar atılır (299.00 → 299). Tümü
src/lib/iyzico.ts içinde:
| Yer | Alan sırası |
|---|---|
initImzaDurumu |
conversationId:token |
retrieveImzaDurumu |
paymentStatus:paymentId:currency:basketId:conversationId:paidPrice:price:token |
webhookImzaDurumu (V3, HPP) |
HMAC(secret, secret + iyziEventType + iyziPaymentId + token + paymentConversationId + status) |
Karar kuralı: imza tutmuyorsa işlem reddedilir; imza alanı hiç yoksa (hesapta kapalıysa) akış sürer ve log'a uyarı düşer — retrieve zaten kimliği doğrulanmış sunucu-sunucu çağrısıdır, bu yüzden imza yokluğu ödemeyi bloklamaz.
Webhook kurulumu
Merchant Portal → Ayarlar → İşyeri Ayarları → İşyeri Bildirimleri →
https://<alan-adı>/api/odeme/webhook (HTTPS zorunlu).
X-IYZ-SIGNATURE-V3 başlığının gönderilmesi ayrıca aktifleştirilmelidir
(entegrasyon@iyzico.com). Aktif değilse başlık gelmez; route yine güvenlidir
çünkü durumu gövdeden değil retrieve'den okur.
iyzico 2xx alana kadar 15 dakika arayla 3 kez dener — bu yüzden işleyemediğimiz durumlarda bile 200 döneriz, yalnızca geçersiz imzada 401.
Test
Sandbox test kartları: https://docs.iyzico.com/en/add-ons/test-cards. Son kullanma tarihi gelecekte olmak kaydıyla SKT ve CVV serbesttir.
Dev panelinden (src/components/dev/dev-panel.tsx) iyzico'ya hiç gitmeden
"ödenmiş sahte sipariş" üretilebilir — sonuç ekranını denemek için.