Kartla Ödeme — 2D
2D ödeme, kartı tek istekte çeker; banka tarafında 3D Secure doğrulaması ve yönlendirme yoktur. Alıcı formdan ayrılmaz, sonuç anında döner. Bedeli şudur: 3D doğrulaması olmadığından sorumluluk devri (liability shift) yoktur.
Bu sayfa Checkout Formu yolu içindir. POST /payments/form/2d ucunu Checkout Form SDK'sı alıcının tarayıcısından kendisi çağırır; sizin bu uca istek yazmanız gerekmez. Yazacağınız kod, sunucunuzda intent oluşturmak ve formu sayfanıza mount etmektir → Checkout Formu.
Kart verisini kendi sunucunuzdan gönderiyorsanız bu sayfa sizin için değildir → Kart — 2D.
Tüm tutarlar minor unit (kuruş) cinsinden tam sayıdır: "amount": 10050 = ₺100,50. Ondalık ya da float göndermeyin.
Nasıl çalışır
Intent oluşturun (sunucunuz)
Step-Up kimlik doğrulamasıyla POST /payments/intents çağırın. Yanıttaki form token'ı yaklaşık 15 dakika geçerlidir ve formun açılacağı origin'e bağlıdır. Bütün alanlar ve 3D ayarları → Checkout Formu.
Formu mount edin (tarayıcı)
Token'ı SDK'ya verip formu sayfanıza yerleştirin. SDK açılışta oturum kanıtını alır (POST /payments/form/session-init) ve risk analizini başlatır (POST /payments/form/live-analyze). Kanıt pg_checkout_session çerezine yazılır; karta dokunan çağrılar bu kanıt olmadan reddedilir.
Alıcı kartı girer
Form kartın marka ve ailesini çözer, taksit tablosunu gösterir ve kartı izole bir iframe'de tek kullanımlık bir token'a çevirir (POST /payments/form/tokenize). Kart numarası sayfanıza hiç açılmaz. Taksit seçilirse çekim tutarı, gösterilen teklife bağlanır → Taksit & BIN.
SDK çekimi yapar
Intent'in 3D kararı 2D ise SDK POST /payments/form/2d çağırır. İşlem risk kontrolünden geçer, uygun sağlayıcıya yönlendirilir ve anında çekilir.
Alıcı sonuç sayfanıza döner
Çekim başarılıysa ve intent'te callbackUrl verdiyseniz SDK alıcıyı imzalı bir form POST'uyla bu adrese gönderir. callbackUrl yoksa form kendi başarı ekranını gösterir. Ret durumunda form hatayı alıcıya gösterir.
Webhook ile teyit edin
payment.captured ya da payment.failed webhook endpoint'inize teslim edilir. Siparişi bu olaya ya da GET /payments/:id sorgusuna göre kapatın.
3D kararı: form 2D'yi ne zaman çağırmaz
2D bir istektir, garanti değildir. Hangi ucun çalışacağını intent'in 3D kararı belirler. Karar intent oluşturulurken aşağıdaki kaynaklardan çözülür ve intent'e sabitlenir:
| Kaynak | Davranış |
|---|---|
Intent'te force3D: true | Her şeyi ezer; ödeme 3D Secure ile işlenir. |
Intent'te force3D: false | Ödeme politika tarafından 3D'ye zorlanmaz; panel ayarını da settings.threeD'yi de ezer. |
Intent'te settings.threeD.mode: "3d" | Bu intent'teki çekimler 3D Secure gerektirir. |
settings.threeD.forceAmountMinor eşiği | Eşik ve üzerindeki tutarlar auto modda da 3D Secure gerektirir. |
| Panel 3D politikası | Intent'te force3D ya da settings.threeD yoksa geçerli olan hesap varsayılanınız. |
Karar 3D ise SDK doğrudan 3D Secure ucunu kullanır. Aynı intent için POST /payments/form/2d çağrısı 409 THREE_D_REQUIRED ile reddedilir; 3D'ye sessiz bir geçiş yapılmaz. SDK bu yanıtı alırsa aynı gövdeyi bir kez POST /payments/form/3d ucuna gönderir ve akış 3D Secure olarak sürer.
Bu alanları intent oluştururken verirsiniz; ayrıntılı anlatım → Checkout Formu.
Sağlayıcı 2D yapamadığında: otomatik 3D Secure
Politikanız 2D dese bile ödemeyi yönlendiren sağlayıcı, anlaşması gereği 2D (non-secure) satış yapamıyor olabilir. Checkout Formu'nda alıcı ekran başında olduğu için platform çekimi reddetmez, 3D Secure'a yükseltir:
POST /payments/form/2dçağrısıCAPTUREDyerine bir 3D yönlendirme yanıtı döner. SDK alıcıyı banka doğrulamasına gönderir; akış oradan itibaren 3D Secure akışı gibi ilerler.- Ödeme
escalationReason: "PROVIDER_2D_UNSUPPORTED"ile işaretlenir. Böylece ödemenin 2D istendiğini ama sağlayıcı yeteneği nedeniyle 3D'ye çıktığını ayırt edebilirsiniz. - Intent 3D'ye döner. Aynı intent'e yeniden
POST /payments/form/2dgöndermek409 THREE_D_REQUIREDile reddedilir.
Intent'te açıkça force3D: false göndermiş olsanız da sağlayıcının 2D yapamaması bu tercihi ezer ve ödeme 3D Secure'a yükseltilir. 2D seçtiğiniz bir intent'in de 3D Secure ile tamamlanabileceğini varsayın; sonuç sayfanız ve webhook işleyiciniz iki durumu da karşılamalıdır.
Uç başvurusu — POST /payments/form/2d
Bu bölüm başvuru içindir: gövdeyi SDK kurar ve gönderir.
Kimlik doğrulama Authorization başlığıyla değil, iki parçayla yapılır:
- Gövdedeki
token: intent yanıtındaki form token'ı. - Oturum kanıtı:
pg_checkout_sessionçerezi. Çerez taşınamayan ortamlarda (WebView, üçüncü taraf çerez engeli) aynı kanıt gövdedecheckoutSessionProofalanıyla gönderilir.
Alanlar
POST /payments/form/3d aynı gövdeyi kullanır.
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
token | string | Evet | Intent yanıtındaki form token'ı. |
installment | integer | Evet | Taksit sayısı; peşin için 1. |
paymentCards | object | Evet | Kart. Ham kart alanları (cardHolderName, cardNumber, expireMonth, expireYear, cvcNumber) ya da POST /payments/form/tokenize yanıtındaki tek kullanımlık token (secureCardToken). Alıcı kartını kaydetmek isterse cardSave: true. |
paymentChannel | enum | Evet | WEB, WEEMOBILE, MOBILE, MOBILE_WEB, MOBILE_ANDROID, MOBILE_WINDOWS, MOBILE_TABLET, MOBILE_PHONE, MOBILE_IOS |
browserFingerprint | string | Evet | Tarayıcı parmak izi; SDK üretir. |
installmentQuoteToken | string | Taksitte evet | Taksit tablosundan dönen bağlayıcı teklif token'ı. installment 1'den büyükse sunucu bu token'ı ister. |
checkoutSessionProof | string (en çok 2048) | Hayır | Oturum kanıtı; çerez taşınamayan ortamlarda gövdede gönderilir. |
liveSessionTraceId | string | Hayır | Risk analizinin döndürdüğü iz kimliği. |
gsmNumber | string | Hayır | Alıcı Koruması seçildiğinde alıcının telefon numarası. |
buyerProtected | boolean | Hayır | Alıcının Alıcı Koruması'nı seçip seçmediği. |
2D çekimde kart kaydedilmez. Alıcı "kartımı kaydet" kutusunu işaretlese de ödeme etkilenmez; kart kaydı yalnız 3D Secure ile yapılır.
Örnek gövde
SDK'nın gönderdiği gövde (secure-fields modunda):
{
"token": "<intent yanıtındaki form token'ı>",
"installment": 1,
"paymentCards": {
"secureCardToken": "<tokenize yanıtındaki cardToken>"
},
"paymentChannel": "WEB",
"browserFingerprint": "<parmak izi>"
}Gövdeyi Checkout Form SDK'sı kurar. SDK, alıcıya gösterdiği toplamı da formun iç alanı olarak ekler; bu sizin göndereceğiniz bir tutar değildir. Çekilen tutarı sunucu, intent'teki amount'tan ve taksitte bağlayıcı teklifteki vade farkından hesaplar.
Yanıt
Başarılı çekim 200 döner:
{
"status": "success",
"code": "PAYMENT_CAPTURED",
"message": "Payment processed",
"data": {
"id": "9c6f2b1a-4e8d-4a3f-b5e6-2d7c1a9b8e30",
"orderId": "ORD-9988",
"amount": 10050,
"currency": "TRY",
"status": "CAPTURED"
},
"statusCode": 200,
"requestId": "…"
}data.status2D'de normalde nihaidir: başarıdaCAPTURED, retdeFAILED.data.amountçekilen tutardır: intent'tekiamount, taksitli ödemede sistemin eklediği vade farkıyla birlikte.callbackUrlverdiyseniz yanıt, alıcıyı sonuç sayfanıza taşıyan imzalı formu da içerir. SDK bu formu kendisi gönderir. Gelen alanlar 3D Secure dönüşüyle aynıdır → Sonuç sayfanıza gelen imzalı POST.- Sağlayıcı yeteneği nedeniyle 3D'ye yükseltilen çekim, 3D Secure ucunun yanıtını döner (
status: "partial",AWAITING_3D) → Kartla Ödeme — 3D Secure › Yanıt. - Sonucu henüz kesinleşmemiş bir işlem
status: "partial"(HTTP202) ile döner; nihai durumu webhook teslim eder.
Tarayıcıdan gelen sonuç bilgilendiricidir. Siparişi payment.captured webhook'una ya da GET /payments/:id sorgusuna göre ödenmiş sayın.
Ön provizyon
Formda ön provizyonu ayrıca istemezsiniz: intent'i POST /payments/intents ile oluştururken "preauth": true gönderin. Form çekimi bu karara göre yapar; ödeme başarılı olursa CAPTURED yerine AUTHORIZED olur ve payment.authorized gönderilir. Ön provizyonu desteklemeyen sağlayıcılar adaylardan çıkarılır; uygun sağlayıcı kalmazsa ödeme FAILED olur ve ret kodu PREAUTH_NOT_SUPPORTED'dır.
Capture, void ve 7 günlük süre: Ön Provizyon, Capture & İptal.
Hatalar
Hata yanıtları ortak hata zarfını kullanır; message'a göre değil code'a göre dallanın → Hata Yönetimi.
| Durum | Kod | Ne yapmalı |
|---|---|---|
| Gövde doğrulamadan geçmedi | 400 VALIDATION_ERROR | Güncel SDK'yı kullanın; gövdeyi SDK kurar. |
| Intent'in 3D kararı 3D | 409 THREE_D_REQUIRED | 2D'yi yeniden denemeyin. SDK aynı gövdeyi POST /payments/form/3d ucuna gönderir. |
| Form token'ı geçersiz | 401 payment.checkout.session_invalid | Yeni intent oluşturup formu yeniden mount edin. |
| Form token'ının süresi doldu (yaklaşık 15 dakika) | 401 payment.checkout.session_expired | Yeni intent oluşturup formu yeniden mount edin. |
| Form, intent'in bağlı olduğu origin dışında açıldı | 401 payment.checkout.origin_mismatch | Intent'i, formu açtığınız sayfanın origin'iyle oluşturun → Checkout Formu. |
| Oturum kanıtı yok ya da geçersiz | 401 payment.checkout.proof_missing | Formu SDK ile açın. Çerez taşınamayan ortamlarda kanıt checkoutSessionProof ile gövdede gönderilir. |
| Oturum kanıtı bu oturuma ait değil | 401 payment.checkout.proof_mismatch | Formu yeniden açın. |
| Form token'ı bu ödemeye ait değil | 401 payment.checkout.token_mismatch | Formu intent yanıtındaki token'la yeniden açın. |
| Tek kullanımlık kart token'ı geçersiz ya da kullanılmış | 401 payment.secure_card.invalid_token | Alıcı kartı yeniden girer; SDK yeni token alır. |
| İşlem güvenlik kontrolünden geçemedi | 409 payment.intent.live_risk_blocked | Yeniden deneme sonucu değiştirmez. |
| Bu ödeme denemesi kapandı (ödeme sonuçlandı) | 409 payment.intent.attempt_closed | Yeni intent oluşturup formu yeniden açın. |
Intent kart dışı bir yöntemle açılmış (ör. paymentMethod: "WALLET") | 409 payment.method.intent_not_card | Bu intent kartla ödenemez; intent'i paymentMethod göndermeden ya da "CARD" ile oluşturun. Intent'e dokunulmadı, kendi yönteminden ödenebilir → Checkout Formu — Payment. |
| Ön provizyonu destekleyen sağlayıcı yok | Ödeme FAILED, kod PREAUTH_NOT_SUPPORTED | Para bloke edilmedi; bkz. Ön Provizyon. |
| Taksit teklifi geçersiz ya da süresi doldu | Ödeme FAILED, kod INSTALLMENT_QUOTE_REJECTED | Yeni intent oluşturun; alıcı taksiti güncel tablodan yeniden seçer. |
| Formun alıcıya gösterdiği toplam, sunucunun hesapladığı çekim tutarıyla eşleşmiyor | Ödeme FAILED, kod CLIENT_PRICE_DIVERGENCE | Formun güncel SDK ile açıldığından emin olun ve yeni intent oluşturun. |
| Sağlayıcı reddi (yetersiz bakiye, geçersiz kart …) | Ödeme FAILED | Form reddi alıcıya gösterir. Aynı intent'le yeniden çekim yapılamaz; alıcı yeniden ödemek isterse yeni intent oluşturun. |
| Geçici altyapı hatası | 503 payment.dependency.unavailable, payment.credential.resolution_failed, payment.lock.unavailable | Geçicidir; alıcı kısa süre sonra yeniden deneyebilir. |
Webhook'lar
| Event | Ne zaman |
|---|---|
payment.captured | Çekim tamamlandı, para çekildi |
payment.failed | Çekim reddedildi |
payment.authorized | Ön provizyonlu intent'te tutar bloke edildi (AUTHORIZED); para henüz çekilmedi |
Teslimat ve imza doğrulaması → Webhook'lar.
Sonraki adımlar
- Kartla Ödeme — 3D Secure: 3D kararı ya da sağlayıcı yeteneği 3D gerektirdiğinde akış
- Checkout Formu: intent oluşturma,
force3Dvesettings.threeD - Taksit & BIN: gösterilen tutar, çekilen tutardır
- İade: çekim sonrası para iadesi