Checkout Formu
Hosted checkout formu, kart ödemesi almanın önerilen yoludur: sunucunuz POST /payments/intents ile bir payment intent oluşturur, alıcı ödemeyi Lunixi'nin formunda tamamlar ve kart verisi altyapınıza hiç dokunmaz. Bu sayfa intent create'in eksiksiz referansıdır — tüm alanlar, istek bazlı politika override'ları, yanıt ve sonrasında tarayıcıda olanlar.
Tüm tutarlar minor-unit (kuruş) cinsinden tam sayıdır: "amount": 10050 = ₺100,50. Bu kural amount, basketItems[].price ve settings.threeD.forceAmountMinor için geçerlidir.
Nasıl çalışır
Intent oluşturun (sunucu)
Step-Up auth ile POST /payments/intents (Bearer + Ed25519 imza + Idempotency-Key). Yanıt, allowedOrigin'inize bağlı, ~15 dakika geçerli bir form token'ı döner.
Formu mount edin (tarayıcı)
Sayfanızda formun çizileceği boş bir <div> açın; SDK içini kendisi doldurur.
<div id="lunixi-checkout-form"></div>
<script src="https://cdn.lunixi.com/lunixi-checkout.min.js"></script>
<script>
const checkout = Lunixi.checkout.create({
type: 'payment',
target: 'lunixi-checkout-form',
options: { token: 'intent yanıtındaki token' },
});
checkout.mount('#lunixi-checkout-form');
</script>mount() önce getElementById, bulamazsa querySelector dener — 'lunixi-checkout-form' ve '#lunixi-checkout-form' aynı işi yapar. DOM elemanı da geçirebilirsiniz.
Hedef <div>'i boş bırakın ve sabit yükseklik vermeyin. SDK monte ederken içeriği temizler; form yüksekliği de kart girildikçe değişir (taksit tablosu açılır) ve SDK bunu kendisi ayarlar.
Yalnız kart alanını (tek satır, PCI kapsamı dar) istiyorsanız createCardField varyantını kullanın → Kart Alanı.
Fraud bootstrap & session proof
Form POST /payments/form/live-analyze çağırır; bu çağrı oturumu analiz eder ve bir session-proof cookie set eder. Karta dokunan çağrılar bu cookie olmadan reddedilir. Yaşam döngüsü sinyalleri /payments/form/live-event üzerinden akar.
BIN & taksit
Alıcı kart numarasını yazarken form; kartın marka ve ailesini (POST /form/bin/info) ve taksit tablosunu (POST /form/bin/installments) çözer. Taksit quote'u bağlayıcı bir quoteToken döner — alıcıya gösterilen tutar, çekilen tutarın ta kendisidir. Bkz. Taksit & BIN.
Tokenize
Kart alanları izole bir secure-fields iframe'inde yaşar. POST /payments/form/tokenize girilen kartı tek kullanımlık bir kart token'ına çevirir (paymentCards.secureCardToken olarak geri gönderilir) — PAN, merchant sayfasına asla açılmaz.
Çekim — 2D veya 3D
Form POST /payments/form/2d veya POST /payments/form/3d çağırır (token, session proof ve taksit seçildiyse installmentQuoteToken ile). Hangisinin çalışacağına geçerli 3D politikası karar verir — aşağıdaki force3D bölümüne bakın. Karar, intent oluşturulurken intent'e dondurulur; 3D zorunluysa doğrudan /form/2d denemesi 409 THREE_D_REQUIRED ile reddedilir (SDK bu durumda 3D endpoint'ini kullanır).
3D doğrulaması & sonuç
3D'de ödeme AWAITING_3D'ye geçer ve alıcı banka doğrulaması için GET /payments/threed/:token adresine (public, tek kullanımlık token) yönlendirilir. Ardından callback çözülür ve sonuç callbackUrl'inize bilgilendirici bir form POST (_signature + _timestamp platform bütünlük alanlarıyla) olarak iletilir; otorite kaynak olan webhook'lar da tetiklenir — bkz. 3D Form.
3D Secure gösterimi
Panelde Ödeme → Form Ayarları → 3D Secure → 3D Secure gösterimi ile bankanın doğrulama ekranının nasıl açılacağını seçersiniz:
| Seçenek | Ne olur |
|---|---|
| Form içinde (varsayılan) | Bankanın doğrulama ekranı formun üstünde bir pencerede açılır. Doğrulama bitince pencere kapanır ve form sıradaki adıma geçer; alıcı sayfanızdan ayrılmaz |
| Ayrı sayfada | Alıcı bankanın sayfasına yönlendirilir. Banka alıcıyı Lunixi'nin ödeme devam sayfasına döndürür; kalan adımlar orada yürür ve ödeme bitince alıcı sonuçla callbackUrl'inize döner |
- Otomatik ayrı sayfa: Banka doğrulama ekranının pencerede açılmasına izin vermezse 3D Secure aynı kart için ayrı sayfada otomatik olarak yeniden başlatılır. Bunun için bir şey yapmanız gerekmez.
- Seçim parçalı ödemedeki kart doğrulamalarında uygulanır. Tek kartlı ödemede 3D Secure akışı 3D Form sayfasındaki gibidir.
- Değişiklik yalnız yeni başlayan ödemeleri etkiler; süren bir ödeme başladığı seçimle tamamlanır.
Devam sayfası, callbackUrl'inize gelen alanlar ve hata kodları: Parçalı Ödeme › 3D Secure ve devam sayfası.
İstek
POST /payments/intents — Step-Up auth.
Alanlar
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
amount | integer (minor unit) | Evet | Tek tutar alanı, örn. 10050 = ₺100,50. Sepet toplamıdır: alıcının ödediği ürün ve hizmet bedeli, vade farkı hariç. Min 1. Bkz. Tutar ve taksit. |
currency | string (ISO 4217) | Evet | örn. "TRY" |
orderId | string | Evet | Benzersiz sipariş referansınız |
callbackUrl | string | Hayır | 3D / async sonucun POST edileceği adres (HMAC-imzalı) |
locale | string | Hayır | Form dili. Varsayılan "tr". |
buyer | object | Hayır | Alıcı bilgileri — aşağıya bakın |
shippingAddress | object | Hayır | Adres objesi — aşağıya bakın |
billingAddress | object | Hayır | Adres objesi — aşağıya bakın |
basketItems | array | Hayır | Sepet satırları — aşağıya bakın |
paymentGroup | string | Hayır | örn. "PRODUCT" |
paymentChannel | string | Hayır | örn. "WEB" |
method | enum | Hayır | Ödeme tipi; varsayılan normal ödeme. Pazaryeri split ödemeleri kendi endpoint'ini kullanır — bkz. Pazaryeri. |
description | string | Hayır | Müşteriye görünen çekim açıklaması |
customerId | string | Hayır | Müşteri referansınız — Ödeme Listeleme'de filtreleme sağlar |
metadata | object | Hayır | Ödemeyle birlikte geri dönen serbest key/value verisi |
force3D | boolean | Hayır | Ödeme bazlı 3D anahtarı — her politikayı ezer, aşağıya bakın |
preauth | boolean | Hayır | true → ön provizyon: tutar alıcının kartında bloke edilir, ödeme AUTHORIZED olur; sonra capture ya da void yaparsınız. Verilmezse ya da false ise tutar hemen çekilir. Aşağıya bakın |
settings | object | Hayır | İstek bazlı form ayarı override'ı — aşağıya bakın |
buyer objesi
buyer opsiyoneldir. Gönderirseniz aşağıdaki "Evet" alanlarının hepsi dolu olmalıdır. Checkout Formu intent'inde (POST /payments/intents, POST /payments/marketplace/intents) bu zorunluluk yoktur: alanların hepsi isteğe bağlıdır, gönderdiğiniz alanların tipi ve uzunluğu doğrulanır.
| Alan | Tip | Zorunlu | Örnek |
|---|---|---|---|
id | string | Hayır | CUST-1 |
name | string | Evet | Ada |
surname | string | Evet | Yılmaz |
identityNumber | string | Evet | 11111111111 |
email | string (e-posta) | Evet | [email protected] |
gsmNumber | string | Evet | +905000000000 |
city | string | Evet | İstanbul |
country | string | Evet | Turkey |
zipCode | string | Evet | 34732 |
ip | string | Evet | Alıcının IP adresi |
registrationDate | string | Hayır | 2024-04-21 15:12:09 |
lastLoginDate | string | Hayır | 2026-10-05 12:43:35 |
registrationAddress | string | Hayır | Kayıtlı adres |
Checkout Formu'ndaki uzunluk sınırları ve alıcı bilgilerinin nerede kullanıldığı: Alıcı Bilgileri.
shippingAddress / billingAddress objesi
shippingAddress ve billingAddress aynı yapıdadır. Nesneyi gönderirseniz beş alan da zorunludur.
| Alan | Tip | Örnek |
|---|---|---|
contactName | string | Ada Yılmaz |
address | string | Altunizade Mah. … |
city | string | İstanbul |
country | string | Turkey |
zipCode | string | 34742 |
İki adresin farkı ve hangisinin ne zaman kullanıldığı: Adres Bilgileri.
basketItems[] objesi
| Alan | Satır içinde zorunlu | Örnek |
|---|---|---|
id | Evet | "BI101" |
price | Evet — integer, minor unit | 10050 |
name | Evet | "Binocular" |
category1 | Evet | "Collectibles" |
category2 | Hayır | "Accessories" |
itemType | Evet — "PHYSICAL" veya "VIRTUAL" | "PHYSICAL" |
Kalemlerin price toplamı amount'a eşit olmalıdır. Kalem kuralları, basketItems.0.price gibi hata alan yolları ve isteğe bağlı sigorta alanları: Sepet Kalemleri.
Tutar ve taksit
amounttek tutar alanıdır. Tutarı yalnızamountile gönderin; kaldırılan tutar alanları400payment.amount.field_removedalır.- Intent'te taksit alanı yoktur; gönderilirse istek
400 VALIDATION_ERRORalır. Alıcı taksiti formda seçer. - Vade farkını siz göndermezsiniz. Sistem vade farkını alıcının seçtiği bağlayıcı taksit teklifinden hesaplar ve çekilen tutara ekler: çekilen tutar =
amount+ vade farkı. - Yanıtlardaki ve webhook'lardaki tutar alanları (
data.amount,capturedAmountMinor…) çekilen tutarı gösterir; taksitli ödemede vade farkı dahildir.
force3D — en üst düzey override
force3D, ödeme bazlı 3D anahtarıdır:
force3D: true→ bu ödeme 3D Secure ile işlenir — panel politikasından vesettings.threeDiçindeki her şeyden bağımsız olarak.force3D: false→ bu ödeme politika tarafından 3D'ye zorlanmaz.- Verilmezse → geçerli politika karar verir (panel ayarları; istek bazında
settings.threeDile override edilebilir).
Açıkça verilen force3D her şeyi ezer — panel 3D politikasını da, tutar eşiği dahil settings.threeD override'ını da.
preauth — ön provizyon
Formu oluştururken "preauth": true gönderirseniz bu ödeme ön provizyon olarak alınır:
- Alıcı formda ödemeyi tamamlayınca tutar kartında bloke edilir, çekilmez; ödeme
AUTHORIZEDolur vepayment.authorizedwebhook'u gelir. - Formun yaptığı çekim (2D, 3D Secure ya da kart dışı yöntem) bu karara uyar; formda ayrıca bir şey göndermezsiniz.
- Formda yalnız ön provizyonu destekleyen ödeme yöntemleri gösterilir.
- Tutarı sonra capture ile çekersiniz ya da void ile serbest bırakırsınız; süresi içinde capture edilmeyen bloke
EXPIREDolur.
{
"amount": 10050,
"currency": "TRY",
"orderId": "ORDER-1001",
"callbackUrl": "https://merchant.example.com/payment/callback",
"preauth": true
}Süre, desteklenen yöntemler ve hatalar: Ön Provizyon, Capture & İptal.
settings — istek bazlı form ayarı override'ı
settings, merchant panelinizdeki form ayarlarının üzerine yalnızca bu intent için uygulanır. Override kuralı alana göre değişir:
| Alan | Tip | Davranış |
|---|---|---|
settings.paymentMethods | string[] — örn. ["card"] | Bu formda gösterilecek yöntemler. Yalnız daraltır: geçerli küme panel kümesiyle kesişimdir — panelde kapalı bir yöntem buradan açılamaz. |
settings.threeD.mode | "2d" | "3d" | "auto" | Bu intent için 3D modu. Tam ikame: settings.threeD gönderilmişse, bu intent için panelin 3D yapılandırmasının yerine geçer (sizin imzalı, müşteri-bazlı kararınız). force3D verilmişse tamamen yok sayılır. |
settings.threeD.forceAmountMinor | string (minor unit) | Tutar eşiği: bu tutar ve üzeri ödemeler 3D'ye zorlanır. "0" = her ödeme 3D; null = eşik yok. settings.threeD gönderildiğinde mode ile birlikte ikame edilir. |
settings.buyerProtection.enabled | boolean | Bu ödemede Alıcı Koruması çalışsın mı. Tam ikame: bu intent-bazlı karar panel varsayılanının yerine geçer — panelde kapalı olsa bile true göndermek bu formda Alıcı Koruması seçeneğini gösterir. Aşağıdaki kutuya bakın. |
Güvenlik-hassas form ayarları (identityCheck, cardStorage, installmentTab) istek bazında override edilemez — her zaman panelden gelir.
Alıcı Koruması nedir? Alıcı Koruması bir onay-linki akışıdır: alıcı, satın almayı bir onay linki üzerinden teyit eder; ödemeye açık bir alıcı-onayı adımı eklenir. 3D Secure değildir ve onun yerine geçmez — 3D banka tarafında bir kimlik doğrulamasıdır; Alıcı Koruması Lunixi tarafında bir teyit katmanıdır. İkisi birbirinden bağımsız yapılandırılır.
Örnek istek
curl -X POST "https://api-gateway.lunixi.com/api/v1/payments/intents" \
-H "Authorization: Bearer at_live_5f3e2b1a..." \
-H "Content-Type: application/json" \
-H "X-Key-Id: key_01JZ8H2M4Q" \
-H "X-Date: 2026-07-06T12:00:00.000Z" \
-H "X-Nonce: 9f8d2c4e-1a3b-4c5d-8e7f-0a1b2c3d4e5f" \
-H "Digest: SHA-256=k6I5cUt...=" \
-H "X-Signature: MEUCIQDx...==" \
-H "Idempotency-Key: order-ORD-9988-attempt-1" \
-d '{
"amount": 10050,
"currency": "TRY",
"orderId": "ORD-9988",
"callbackUrl": "https://shop.example.com/payment/result",
"customerId": "c_98765432",
"description": "Order #9988 payment",
"buyer": {
"name": "John", "surname": "Doe",
"identityNumber": "12345678901",
"email": "[email protected]", "gsmNumber": "+905350000000",
"city": "İstanbul", "country": "Turkey",
"zipCode": "34732", "ip": "85.34.78.112"
},
"basketItems": [
{ "id": "BI101", "price": 10050, "name": "Binocular",
"category1": "Collectibles", "itemType": "PHYSICAL" }
],
"settings": {
"paymentMethods": ["card"],
"threeD": { "mode": "auto", "forceAmountMinor": "500000" },
"buyerProtection": { "enabled": true }
}
}'Yanıt
201 Created:
{
"status": "success",
"code": "CHECKOUT_INITIALIZED",
"data": {
"paymentId": "9c6f2b1a-4e8d-4a3f-b5e6-2d7c1a9b8e30",
"token": "eyJhbGciOiJIUzI1NiIs...",
"checkoutFormContent": "<script>…</script>"
}
}| Alan | Açıklama |
|---|---|
paymentId | Ödeme id'si — GET /payments/:id, capture, void, refund için kullanın |
token | Form token'ı. Tarayıcıda checkout SDK'sına verin. Tek amaçlıdır. |
checkoutFormContent | Hosted checkout SDK'sını bu token'la yükleyip mount eden, sayfaya gömülmeye hazır bootstrap <script> |
Token origin'e bağlıdır (metadata.allowedOrigin / callbackUrl origin'inize) ve süresi dolar — varsayılan 15 dakika. Süresi dolan token → yeni intent oluşturun.
Hatalar
| Status | Durum | Ne yapmalı |
|---|---|---|
400 | Validasyon hatası (eksik amount/currency/orderId, tam sayı olmayan tutar, bozuk settings) | Hata mesajındaki alanı düzeltin; tutarların minor-unit tam sayı olduğunu unutmayın |
401 | Eksik/geçersiz Step-Up header'ları, süresi geçmiş X-Date, tekrar kullanılan nonce, hatalı imza | Bkz. Kimlik doğrulama hataları |
403 | Bearer key ile imza anahtarı uyuşmazlığı (AUTH_MERCHANT_MISMATCH) | Aynı merchant & environment key'lerini kullanın |
401 (form çağrıları) | Form token geçersiz veya süresi dolmuş (~15 dk) | Yeni intent oluşturun ve formu yeniden mount edin |
409 THREE_D_REQUIRED (/payments/form/2d üzerinde) | Bu ödeme için 3D zorunlu (force3D, eşik veya mode gereği) ama 2D çekim denendi | 3D yolunu izleyin — form SDK'sı bunu otomatik yapar |
/payments/form/2d'den 3D redirect döndü (customer-present SALE) | Seçilen sağlayıcı/credential 2D yapamıyor; çekim otomatik olarak 3DS'e yükseltildi (escalationReason: "PROVIDER_2D_UNSUPPORTED") | 3D redirect alanlarını ele alın — bkz. 2D Form › sağlayıcı yeteneği |
Tekrarlanan Idempotency-Key | Orijinal yanıt döner, ikinci çekim olmaz | Beklenen davranış — güvenle tekrar deneyebilirsiniz |
Webhook'lar
Checkout formu akışı, sonuca göre şu eventleri üretir:
payment.captured— çekim tamamlandı, para çekildi (2D, veya doğrulama sonrası 3D)payment.authorized— tutar bloke edildi, authorize-sonra-capture kurulumları içinpayment.failed— nihai ret (yapılandırılmış ret detayı içerir)payment.expired— yalnız-authorize bir hold, capture edilmeden süresi doldu
Teslimat ve imza doğrulaması: Webhook'lar.
Sigorta ekleme
Alıcınıza Checkout Formu'nda ürünle birlikte, sizin anlaştığınız sağlayıcının sigortasını sunabilirsiniz. Ödeme isteğinde ayrı bir sigorta parametresi yoktur:
- Sigortayı panelden açarsınız: Sigorta menüsünde sigortayı ve sunacağınız tipi açar, Form Ayarları > Sigorta'da formdaki yerini seçersiniz. Bu ayarlar kapalıysa formda sigorta hiç görünmez; adımlar: Sigorta › Kurulum.
- Hangi sigortanın sunulacağını sepet kalemlerinizdeki isteğe bağlı sigorta alanları belirler; bkz. Sepet Kalemleri › Sigorta alanları.
- Sigortasız ödemeleriniz etkilenmez. Sigorta alanı göndermezseniz ya da sigorta sunulamazsa ödeme her zamanki gibi devam eder.
Ürünün nasıl çalıştığı ve yol seçimi: Sigorta.
Sonraki adımlar
- 3D Form — doğrulama, yönlendirme ve HMAC-imzalı callback detayı
- 2D Form — 3D'siz çekim yolu
- Taksit & BIN — quote-binding: gösterilen tutar == çekilen tutar
- İade · Ön Provizyon, Capture & İptal
- Pazaryeri — aynı form akışı,
sellers[]split ile - Sepet Kalemleri — kalem alanları, hata alan yolları ve sigorta alanları
- Sigorta — alıcınıza ürünle birlikte sigorta sunun