Payment — Tek Uçtan Ödeme
POST /payments/direct/payment, hesabınızda açık olan her ödeme yöntemiyle sunucunuzdan ödeme başlatır: kart, cüzdan, Faturana Yansıt ve Senetle Öde aynı uçtan, aynı sipariş alanlarıyla gelir. Yöntemi paymentMethod alanı seçer; yönteme özgü bilgiler o yöntemin blokunda gönderilir. Alıcının bir şey yapması gerekiyorsa (doğrulama kodu girmek, banka sayfasına gitmek) yanıt bir action taşır. Kesin sonuç her zaman webhook ile de bildirilir.
Bu sayfa, ödemeyi kendi sunucunuzdan başlattığınız Direct API yolu içindir. Ödemeyi Checkout Formu ile alıyorsanız yöntem çağrılarını form yapar → Checkout Formu — Payment. Kart ödemesinin 2D ve 3D Secure kuralları Kart sayfalarındadır.
Tüm tutarlar minor unit (kuruş) cinsinden tam sayıdır: "amount": 5000 = ₺50,00. Ondalık ya da float göndermeyin.
Nasıl çalışır
Açık yöntemleri okuyun
GET /payments/methods hesabınızda açık yöntemleri, her yöntemin sağlayıcılarını, sağlayıcıyı kimin seçtiğini (providerSelectionMode) ve sağlayıcının alıcıdan istediği alanları (inputFields) döner.
Ödemeyi başlatın
POST /payments/direct/payment çağırın: paymentMethod, sipariş alanları ve yalnız o yöntemin bloğu. İstek Step-Up kimlik doğrulaması ve Idempotency-Key taşır.
Aksiyonu tamamlayın
Yanıtta action varsa alıcıdan bekleneni yapın: OTP'de kodu confirm ile gönderin, REDIRECT'te alıcıyı action.redirect.url adresine yönlendirin. action yoksa sonuç yanıttadır ya da sağlayıcıdan beklenir.
Webhook ile teyit edin
Kesin sonuç payment.captured, payment.authorized ya da payment.failed olarak webhook adresinize gelir. Siparişi payment.captured ile teslim edin.
Yöntemler
| Yöntem | paymentMethod | Blok | Alıcı ne yapar | Sayfa |
|---|---|---|---|---|
| Kart | CARD | card | 3D Secure'da banka sayfasında doğrulanır (REDIRECT) | Kart |
| Cüzdan | WALLET | wallet | Telefonuna gelen kodu girer (OTP) | Cüzdanla Öde |
| Faturana Yansıt | MOBILE_BILLING | mobileBilling | Telefonuna gelen kodu girer ve sözleşmeyi onaylar (OTP) | Faturana Yansıt |
| Senetle Öde | PROMISSORY_NOTE | promissoryNote | Borçlu bilgilerini verir; senetler anında düzenlenir (aksiyon yok) | Senetle Öde |
- Bu uçtan bugün yukarıdaki yöntemler başlatılabilir. Payment menüsündeki diğer yöntemler çok yakında eklenecek.
- Bu uç tek yöntemlidir. Bir siparişi birden fazla karta ve yönteme bölmek için Parçalı Ödeme ucunu kullanın.
- Hesabınızda kullanabileceğiniz yöntemler ve sağlayıcılar
GET /payments/methodsyanıtındadır. - Tanınmayan yöntem kodu
400payment.method.unknown, bu uçta kullanılamayan yöntem400payment.method.not_supportedalır. İstek hiçbir koşulda başka bir yönteme ya da karta çevrilmez.
Kimlik doğrulama
POST /payments/direct/payment ve GET /payments/methods Step-Up ister: Authorization: Bearer at_… token'ınız ve isteğin Ed25519 imzası.
| Başlık | Değer |
|---|---|
Authorization | Bearer at_test_… (test) ya da Bearer at_live_… (canlı) |
X-Key-Id | Kayıtlı Ed25519 public key'inizin kimliği |
X-Date | ISO 8601 istek zamanı; sunucu saatine göre ±5 dakika içinde |
X-Nonce | İstek başına benzersiz, tek kullanımlık değer |
Digest | Gövdeli isteklerde ham JSON gövdesinin SHA-256=<base64> özeti |
X-Signature | Kanonik dizgi üzerinde Base64 Ed25519 imzası |
Idempotency-Key | POST /payments/direct/payment'ta zorunlu, en fazla 200 karakter; bkz. Idempotency |
İmzanın nasıl kurulacağı Kimlik Doğrulama sayfasındadır. Uçlar hesabınızda Payment Gateway ürününün açık olmasını ister.
Açık yöntemleri listeleme
GET /payments/methods hesabınızda açık yöntemleri, her yöntemin sağlayıcılarını, sağlayıcıyı kimin seçtiğini (providerSelectionMode) ve alıcıdan istenen alanları (inputFields) döner; ?paymentMethod= ile tek bir yöntemin satırını okursunuz. Yöntemler ve sağlayıcılar Form Ayarları'ndaki sıranızla gelir. Uç, yanıt alanları, sıra ve sağlayıcı seçim kuralları: Yöntemleri Listeleme.
Yöntem alanları (inputFields)
Bloktaki alanları sağlayıcının inputFields tanımı belirler; değerleri tanımdaki key adıyla gönderirsiniz. Tanımın alanları ve değer tipleri: Yöntemleri Listeleme › Yöntem alanları.
"mobileBilling": { "providerCode": "<providerCode>", "gsmNumber": "+905321234567" }- Tanımda olmayan bir anahtar, eksik zorunlu alan ya da tipe uymayan değer
400payment.method.block_invalidalır. Sorunlu alandetails.field(ör.mobileBilling.gsmNumber) vedetails.reasoniçindedir; bütün ihlallerdetails.errors[]listesindedir. Gönderdiğiniz değer hata yanıtında yer almaz. - İç içe alanlarda yol alanın yerini gösterir:
promissoryNote.address.districtCode,promissoryNote.guarantors[1].identityNumber. details.reasondeğerleri:unknown_field,required,not_applicable(requiredWhenkoşulu tutmuyorken gönderilen alan),invalid_type,invalid_format,too_short,too_long,invalid_option,too_few_items,too_many_items(GROUPöğe sayısı). Yöntemin kendine özgü sebepleri yöntem sayfasındadır; örneğin Senetle Öde.- Değerler yalnız sağlayıcıya iletilir; ödeme kaydında saklanmaz.
Adres sözlüğü
ADDRESS alanının il, ilçe ve mahalle kodları Lunixi adres sözlüğündendir. Sözlük uçları herkese açıktır: kimlik doğrulaması istemez ve kişisel veri döndürmez. Yanıtlar bir gün önbelleğe alınabilir.
| Uç | Sorgu | Döner |
|---|---|---|
GET /api/v1/reference/tr-address/provinces | — | İller: code "01"–"81" |
GET /api/v1/reference/tr-address/districts | provinceCode (zorunlu, "01"–"81") | İlin ilçeleri |
GET /api/v1/reference/tr-address/neighborhoods | districtCode (zorunlu, rakamlar) | İlçenin mahalleleri |
GET https://api-gateway.lunixi.com/api/v1/reference/tr-address/districts?provinceCode=06{
"status": "success",
"code": "SUCCESS",
"message": "…",
"data": {
"items": [
{ "code": "<districtCode>", "name": "<ilçe adı>" }
]
},
"statusCode": 200,
"requestId": "…"
}- Kodları sözlükten okuyun ve alıcıya adlarıyla seçtirin; kodu elle üretmeyin. Mahalle, ilçe ve il birbirine bağlı değilse istek
400 payment.method.block_invalidalır (….address.neighborhoodCode,invalid_option). - Geçersiz
provinceCodeya dadistrictCodesorgusu400alır. Sözlükte kaydı olmayan bir il ya da ilçe için liste boş döner.
İstek
POST https://api-gateway.lunixi.com/api/v1/payments/direct/payment
Content-Type: application/jsonAlanlar
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
paymentMethod | string | Evet | Yöntem kodu: CARD, WALLET, MOBILE_BILLING, PROMISSORY_NOTE |
card | object | CARD'da | Kart bilgisi; bkz. card |
wallet | object | WALLET'ta | Cüzdan bloğu; bkz. Cüzdanla Öde |
mobileBilling | object | MOBILE_BILLING'de | Faturana Yansıt bloğu; bkz. Faturana Yansıt |
promissoryNote | object | PROMISSORY_NOTE'ta | Senet bloğu: vade planı ya da senet sayısı ve borçlu alanları; bkz. Senetle Öde |
force3D | boolean | Hayır | Yalnız CARD ile. true: 3D Secure; verilmezse ya da false ise 2D. Bkz. Kart |
installment | integer | Hayır | Yalnız CARD ile; taksit sayısı, varsayılan 1 |
installmentQuoteToken | string | Hayır | Yalnız CARD ile; taksit quote'unun bağlayıcı token'ı |
preauth | boolean | Hayır | true: ön provizyon, ödeme AUTHORIZED olur. Bkz. Ön provizyon |
callbackUrl | string | Hayır | http ya da https, en fazla 2048 karakter. Alıcı tarayıcısının sonuçla döneceği adres (REDIRECT aksiyonu; ör. kart 3D Secure) |
Sipariş alanları
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
amount | integer | Evet | Tutar, minor unit tam sayı; en az 1. Sepet toplamıdır: alıcının ödediği ürün ve hizmet bedeli, vade farkı hariç. basketItems gönderirseniz kalemlerin price toplamına eşit olmalıdır. Kartta taksit seçilirse vade farkını sistem ekler. Örnek: 10050 |
currency | string (enum) | Evet | ISO 4217 kodu: TRY, USD, EUR, GBP, RUB, AED, SAR, QAR, KWD, JPY, CHF, CAD, AUD, CNY, AZN. Hesabınızda açık olmayan para birimi reddedilir |
orderId | string | Evet | Sizin sipariş numaranız, en fazla 128 karakter. Örnek: ORD-84722 |
customerId | string | Hayır | Sizin müşteri anahtarınız. Cüzdanla ödemede alıcıyı tanımlar; 3D Secure ile kart kaydında kart bu anahtarın altına yazılır. Örnek: cust_7788 |
description | string | Hayır | Ödeme açıklaması |
locale | string | Hayır | Mesaj dili, varsayılan tr |
paymentChannel | string | Hayır | Ödeme kanalı. Örnek: WEB |
paymentGroup | string | Hayır | Ürün grubu. Örnek: PRODUCT |
buyer | object | Hayır | Alıcı bilgisi; bkz. buyer |
shippingAddress | object | Hayır | Teslimat adresi; bkz. Adres |
billingAddress | object | Hayır | Fatura adresi; bkz. Adres |
basketItems | array | Hayır | Sepet kalemleri; bkz. basketItems[] |
metadata | object | Hayır | Kendi kayıtlarınız için serbest anahtar-değer nesnesi. Ön provizyonu metadata ile değil preauth alanıyla isteyin |
Tutar yalnız amount ile gönderilir; kaldırılan tutar alanları 400 payment.amount.field_removed alır. Tanımlı olmayan bir alan gönderirseniz istek 400 VALIDATION_ERROR ile reddedilir.
buyer.gsmNumber, yöntem alanlarının prefill kaynağıdır: cüzdan ve Faturana Yansıt bloğunda telefon gönderilmezse kullanılır. metadata ödeme kararlarında okunmaz: örneğin metadata içine yazılan bir yöntem ya da ön provizyon değeri ödemeyi değiştirmez.
card
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
cardHolderName | string | Ham kartta | Kart üzerindeki ad soyad |
cardNumber | string | Ham kartta | Kart numarası |
expireMonth | string | Ham kartta | İki haneli ay, 01–12 |
expireYear | string | Ham kartta | İki haneli yıl. Örnek: 30 |
cvcNumber | string | Ham kartta | 3 ya da 4 haneli güvenlik kodu. Kayıtlı kart çekiminde de bankaların çoğu ister |
cardUserKey | string | Kayıtlı kartta | Kartın kayıtlı olduğu müşteri anahtarı |
cardToken | string | Kayıtlı kartta | Kayıtlı kartın kalıcı referansı (storedCardToken). Checkout Formu'nun tek kullanımlık kart token'ı burada kullanılamaz |
cardSave | boolean | Hayır | true: kart, ödeme başarılı olursa customerId anahtarının altına kaydedilir. Yalnız 3D Secure istekte (force3D: true) gönderilebilir; 2D istekte 400 payment.card.save_requires_3ds alır |
cardName | string | Hayır | Kaydedilen karta verdiğiniz ad; cardSave: true ile birlikte. Örnek: İş kartım |
expireMonthveexpireYeargönderildiğinde iki haneli olmalıdır.- Ham kartla çekimde
cardHolderName,cardNumber,expireMonth,expireYearvecvcNumbergönderilir. Kayıtlı kartla çekimde ham kart alanları yerinecardUserKeyvecardTokengönderilir.
buyer
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 |
Zorunluluk kuralı, customerId ile farkı ve hata alan yolları: Alıcı Bilgileri.
Adres
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 hata alan yolları: Adres Bilgileri.
basketItems[]
| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
id | string | Evet | Kalem kodu |
name | string | Evet | Kalem adı |
category1 | string | Evet | Ana kategori |
category2 | string | Hayır | Alt kategori |
itemType | string (enum) | Evet | PHYSICAL ya da VIRTUAL |
price | integer | Evet | Kalem tutarı, minor unit tam sayı, en az 0 |
Kalemlerin price toplamı amount'a eşit olmalıdır; eşit değilse istek 400 VALIDATION_ERROR ile reddedilir. Vade farkı kalemlere yazılmaz.
Kurallar
- Tutar yalnız
amountile gönderilir; kaldırılan tutar alanları400payment.amount.field_removedalır.basketItemsgönderilirse kalemlerinpricetoplamıamount'a eşit olmalıdır; eşit değilse istek400 VALIDATION_ERRORalır. - Kartta taksit seçildiyse (
installment+installmentQuoteToken) vade farkını sistem quote'tan hesaplar ve çekilen tutara ekler: çekilen tutar =amount+ vade farkı. Sorgu ve webhook'taki tutar alanları bu çekilen tutarı gösterir. - Gövdede yalnız
paymentMethod'a karşılık gelen blok bulunur. Başka bir yöntemin bloğu ya da kart dışı yöntemlecard,force3D,installment,installmentQuoteTokengönderilirse istek400 VALIDATION_ERRORalır. - Yöntemin bloğu zorunludur. Bloktaki alanlar sağlayıcının
inputFieldstanımıdır;providerCodedışında tanımda olmayan alan gönderilemez. providerCode: yöntem için tek sağlayıcı bağlıysa gönderilmesi gerekmez. Birden fazla sağlayıcı bağlıysa kuralı yönteminproviderSelectionModedeğeri belirler:BUYER(ör. cüzdan): zorunludur; göndermezseniz400payment.provider.requireddöner ve bağlı kodlardetails.boundProviderCodesiçindedir.PLATFORM(ör. Faturana Yansıt): isteğe bağlıdır. Göndermezseniz platform bağlı sağlayıcılardan birini para çekilmeden önce seçer; hiçbiri bu ödemeyi karşılamıyorsa422payment.provider.none_eligibledöner.
- Seçilen sağlayıcı sabitlenir: hata olursa başka sağlayıcıya, başka yönteme ya da karta geçilmez.
- Form Ayarları'nda yalnız formda kapattığınız sağlayıcı bu uçta kabul edilir; kapatma yalnız Checkout Formu'nu etkiler. Sağlayıcıyı her yerde kapatmak için sağlayıcı bağlantısını kapatın.
- Tanımlı olmayan bir alan (
method,basketId,paymentSource…)400 VALIDATION_ERRORalır.
Örnek istek
# Step-Up imza başlıklarının nasıl hesaplandığı için Kimlik Doğrulama sayfasına bakın.
curl -X POST https://api-gateway.lunixi.com/api/v1/payments/direct/payment \
-H "Authorization: Bearer at_test_5f3e2b1a..." \
-H "Content-Type: application/json" \
-H "X-Key-Id: mk_test_sk_..." \
-H "X-Date: 2026-10-11T09:00:00.000Z" \
-H "X-Nonce: 8d4f2c1e-0a7b-4b3c-9e5d-6f1a2b3c4d5e" \
-H "Digest: SHA-256=..." \
-H "X-Signature: ..." \
-H "Idempotency-Key: ORDER-1002-1" \
-d '{
"paymentMethod": "MOBILE_BILLING",
"orderId": "ORDER-1002",
"amount": 5000,
"currency": "TRY",
"basketItems": [
{ "id": "DIGITAL-1", "name": "Dijital ürün", "category1": "Dijital", "itemType": "VIRTUAL", "price": 5000 }
],
"mobileBilling": { "gsmNumber": "+905321234567" }
}'Yönteme özgü örnekler: Kart — 2D, Kart — 3D Secure, Cüzdanla Öde, Faturana Yansıt, Senetle Öde.
Yanıt
Yanıt ortak zarfla döner; ödemenin kendisi data içindedir. Ödeme başlatma, confirm ve resend aynı biçimi kullanır.
{
"status": "partial",
"code": "CUSTOMER_ACTION_REQUIRED",
"message": "…",
"data": {
"paymentId": "7b0e4c2a-1f3d-4e5b-8a6c-9d0e1f2a3b4c",
"orderId": "ORDER-1002",
"status": "PROCESSING",
"paymentMethod": "MOBILE_BILLING",
"providerCode": "<providerCode>",
"action": {
"id": "act_5c2e9f0a1b3d4e6f7a8b9c0d1e2f3a4b",
"type": "OTP",
"expiresAt": "2026-10-11T09:03:00.000Z",
"otp": { "maskedTarget": "53****67" },
"consent": { "required": true, "url": "https://…" }
}
},
"statusCode": 202,
"requestId": "…"
}| HTTP | Zarf status | Anlamı |
|---|---|---|
200 | success | Ödeme kesinleşti: data.status CAPTURED ya da (ön provizyonda) AUTHORIZED |
202 | partial | Ödeme sürüyor: action alıcıdan bekleneni anlatır ya da sonuç sağlayıcıdan doğrulanıyor (PAYMENT_PENDING_RECONCILIATION) |
400 | failure | Ödeme reddedildi: data.status FAILED; code ret sebebini taşır |
Ret yanıtında details.retryability (RETRYABLE, NON_RETRYABLE, UNKNOWN) aynı isteği yeniden denemenin anlamlı olup olmadığını söyler. İstek hiç işlenmeden reddedildiyse (doğrulama, kimlik, yöntem ya da sağlayıcı hatası) data boştur ve code hatayı anlatır; bkz. Hatalar.
data alanları
| Alan | Tip | Açıklama |
|---|---|---|
paymentId | string | Ödeme kimliği; confirm, resend, capture ve sorgu çağrılarında kullanılır |
orderId | string | Sizin sipariş numaranız |
status | string | Ödemenin durumu; bkz. aşağıdaki tablo |
paymentMethod | string | Yöntem kodu |
providerCode | string | Ödemeyi yürüten sağlayıcının kodu; henüz belli değilse yer almaz |
action | object | Alıcıdan beklenen etkileşim; yalnız açık aksiyon varken bulunur. Bkz. Aksiyonlar |
savedCard | object | Yalnız kartta, bu ödemede yeni kaydedilen kart; bkz. Kart — 3D Secure |
data.status | Ne zaman |
|---|---|
INITIATED | İşletmenin cüzdan programıyla ödemede kod onayı bekleniyor; bkz. Cüzdanla Öde |
PROCESSING | Sağlayıcı alıcının işlemini bekliyor (ör. kod) |
AWAITING_3D | Kartta 3D Secure doğrulaması bekleniyor |
AUTHORIZED | Ön provizyon: tutar bloke edildi |
CAPTURED | Para çekildi |
FAILED | Ödeme reddedildi; para çekilmedi |
NEEDS_RECONCILIATION | Sonuç sağlayıcıyla doğrulanıyor; kesin sonuç webhook ile gelir |
202 yanıtında ya da NEEDS_RECONCILIATION durumunda yeni bir ödeme başlatmayın. Sonuç kesinleşince payment.captured ya da payment.failed gönderilir; durumu GET /payments/:id ile de okuyabilirsiniz.
Aksiyonlar
action, alıcının bir şey yapması gerektiğini anlatır. Bir ödemede aynı anda tek açık aksiyon bulunur. Bir yöntemin döndürebileceği tipler GET /payments/methods yanıtındaki actionTypes alanındadır.
| Tip | Alıcı ne yapar | Siz ne yaparsınız |
|---|---|---|
OTP | Telefonuna gelen kodu girer; consent.required ise sözleşmeyi onaylar | Kodu ve onayı confirm ile gönderin. Kodu yeniden göndermek için resend |
REDIRECT | Sağlayıcının ya da bankanın sayfasına gider ve döner | Alıcıyı action.redirect.url adresine yönlendirin. Confirm gerekmez; sonuç callbackUrl adresinize ve webhook'a gelir |
INPUT | Sağlayıcının ek istediği bilgileri girer (action.input.fields) | Değerleri confirm gövdesinde fields ile gönderin |
Tanımadığınız bir tip gelirse ödemeyi ödenmiş saymayın; sonucu webhook ile bekleyin.
| Alan | Tip | Açıklama |
|---|---|---|
id | string | Aksiyon kimliği; confirm ve resend yolunda kullanılır |
type | string | OTP, REDIRECT, INPUT |
expiresAt | string | Aksiyonun son geçerlilik zamanı (ISO 8601) |
otp.maskedTarget | string | Kodun gönderildiği numaranın maskeli hâli. Örnek: 53****67 |
consent.required | boolean | true ise kod sözleşme onayıyla birlikte gönderilmelidir |
consent.url | string | Alıcıya gösterilecek sözleşmenin adresi |
input.fields | array | INPUT aksiyonunda istenen alanlar; biçimi inputFields ile aynı |
charge | object | Onaydan önce alıcıya gösterilecek tutar kırılımı (minor unit): amount, feeTotal, taxTotal, buyerTotalCharge, currency. buyerTotalCharge = amount + feeTotal + taxTotal |
maskedBusinessName | string | Ödemenin gideceği işletmenin maskeli adı |
stepUpRequired | boolean | Yalnız true iken bulunur: sağlayıcı güçlü doğrulama istedi. Ek girdi beklenmez |
redirect.url | string | REDIRECT aksiyonunda alıcının gideceği adres |
Sağlayıcıya ait oturum bilgileri, referanslar ve doğrulama kodu hiçbir yanıtta, sorguda ya da webhook'ta yer almaz.
Aksiyonu onaylama — confirm
POST https://api-gateway.lunixi.com/api/v1/payments/{paymentId}/actions/{actionId}/confirmAçık aksiyonu sonuçlandırır; yeni bir çekim başlatmaz. Sunucunuzdan çağırırken Kimlik Doğrulama sayfasındaki imza başlıklarını (X-Key-Id, X-Date, X-Nonce, Digest, X-Signature) gönderin; gövdeye token koymayın. Ödeme hesabınıza ait değilse ya da aksiyon bulunamazsa 404 payment.action.not_found döner.
| Alan | Tip | Açıklama |
|---|---|---|
otp | string | Alıcının girdiği kod; yalnız rakam, en fazla 16 karakter |
consentAccepted | boolean | Sözleşme onayı. action.consent.required true ise true gönderilmelidir |
fields | object | INPUT aksiyonunda istenen alanlar. OTP aksiyonunda kod { "otp": "123456" } olarak da gönderilebilir |
{ "otp": "123456", "consentAccepted": true }Yanıt ödeme yanıtıyla aynı biçimdedir:
| Sonuç | HTTP | code | Ne yapmalı |
|---|---|---|---|
| Ödeme tamamlandı | 200 | PAYMENT_CAPTURED ya da PAYMENT_AUTHORIZED | Siparişi payment.captured ile teslim edin |
| Kod reddedildi, hak var | 422 | payment.action.input_rejected | Aksiyon açık kalır; kalan hak details.attemptsRemaining içindedir. Alıcı kodu yeniden girer |
| Hak bitti | 400 | payment.action.attempts_exhausted | Ödeme FAILED olur |
| Sağlayıcı reddetti | 400 | Ret kodu | Ödeme FAILED olur |
| Sonuç doğrulanıyor | 202 | PAYMENT_PENDING_RECONCILIATION | Yeni ödeme açmayın; webhook'u bekleyin |
- Aynı confirm'ü tekrar gönderirseniz ikinci kez sağlayıcıya gidilmez; kaydedilmiş sonuç döner. Bağlantınız koptuysa aynı isteği güvenle tekrarlayabilirsiniz.
- Deneme hakkı aksiyon başınadır; sağlayıcı aksi belirtmedikçe 3'tür.
- Aksiyonun süresi (
expiresAt) dolarsa aksiyon kapanır. Sağlayıcının gönderdiği doğrulama kodunda ödemeFAILEDolur vepayment.failedgönderilir; işletmenin cüzdan programındaki davranış için bkz. Cüzdanla Öde. - Kod ya da onay eksikse istek deneme hakkı yakmadan reddedilir:
payment.action.otp_required,payment.action.consent_required.
Kodu yeniden gönderme — resend
POST https://api-gateway.lunixi.com/api/v1/payments/{paymentId}/actions/{actionId}/resendSağlayıcı destekliyorsa yeni bir kod gönderir. Eski aksiyon kapanır, yanıt (202) yeni action'ı taşır; confirm'de yeni action.id'yi kullanın. Gövde boştur ({}); kimlik doğrulama confirm ile aynıdır.
- Ödeme başına en fazla 3 kez yeniden gönderilebilir; sınır dolunca
422payment.action.resend_limit_reached. - İki gönderim arasında en az 30 saniye olmalıdır; daha erken istek
429payment.action.resend_too_soonalır, bekleme süresidetails.retryAfterSecondsiçindedir. - Yeniden göndermeyi desteklemeyen yöntemde
422payment.action.resend_not_supporteddöner. - Sağlayıcı kodu gönderemezse
502payment.action.resend_faileddöner ve mevcut aksiyon açık kalır. - Eski aksiyonla confirm
409payment.action.replacedalır; yeni aksiyonun kimliğidetails.replacedByActionIdiçindedir.
Ön provizyon
Tutarı çekmeden önce bloke etmek için "preauth": true gönderin. Ödeme başarılı olursa AUTHORIZED olur ve payment.authorized gönderilir; tutarı sonra capture ile çeker ya da void ile blokeyi kaldırırsınız.
- Kartta kurallar: Kart — 2D, Kart — 3D Secure.
- Kart dışı yöntemde sağlayıcının ön provizyonu desteklemesi gerekir (
GET /payments/methodsyanıtındapreauth). Desteklemeyen yöntemde istek ödeme başlamadan422payment.preauth.unsupported_for_methodalır; tutar çekilmez. preauthboolean olmalıdır;metadataiçinde gönderilen bir değer ön provizyon istemez.
Capture, void, süre dolumu ve hatalar: Ön Provizyon, Capture & İptal.
Idempotency
Idempotency-Key bu uçta zorunludur (en fazla 200 karakter). Yoksa istek işlenmeden 400 payment.operation.idempotency_key_required alır. Ödemeyi değil denemeyi tanımlayan bir değer kullanın (örneğin ORDER-1002-1).
| Durum | Sonuç |
|---|---|
| Aynı anahtar, aynı istek | İlk denemenin sonucu döner; ikinci ödeme başlatılmaz. Açık aksiyon varsa yanıtta yine yer alır |
| Aynı anahtar, farklı istek | 409 payment.idempotency.conflict |
| Aynı anahtarla ilk istek hâlâ işleniyor | 429 payment.idempotency.processing; kısa süre sonra aynı anahtarla tekrar deneyin |
Reddedilen bir siparişi yeniden denemek için yeni bir Idempotency-Key gönderin.
Sonuç ve webhook'lar
| Event | Ne zaman |
|---|---|
payment.captured | Para çekildi. Siparişi bunun üzerine teslim edin |
payment.authorized | Ön provizyonda tutar bloke edildi; para henüz çekilmedi |
payment.failed | Ödeme başarısız oldu; para çekilmedi (sağlayıcı kodunun süresinin dolması ya da hakkın bitmesi dahil) |
Ödeme olaylarının data nesnesi paymentMethod ve providerCode alanlarını taşır:
{
"id": "2f6c1b9e-…",
"type": "payment.captured",
"data": {
"intentId": "7b0e4c2a-1f3d-4e5b-8a6c-9d0e1f2a3b4c",
"merchantId": "m_…",
"orderId": "ORDER-1002",
"currency": "TRY",
"status": "CAPTURED",
"paymentMethod": "MOBILE_BILLING",
"providerCode": "<providerCode>",
"capturedAmountMinor": "5000"
}
}| Alan | Açıklama |
|---|---|
data.paymentMethod | Yöntem kodu (CARD, WALLET, MOBILE_BILLING, PROMISSORY_NOTE …) |
data.providerCode | Ödemeyi yürüten sağlayıcının kodu; ödemenin henüz sağlayıcısı yoksa yer almaz |
Ödemeyi GET /payments/:id ile sorguladığınızda yanıt paymentMethod alanını ve açık bir aksiyon varsa action alanını da taşır. Teslimat, imza doğrulama ve diğer alanlar için bkz. Webhook'lar.
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 | Yanıt | Ne yapmalı |
|---|---|---|
| Eksik, hatalı ya da tanımsız alan; yanlış blok | 400 VALIDATION_ERROR | details içindeki alanı düzeltin |
| Kaldırılan bir tutar alanı gönderildi | 400 payment.amount.field_removed | Tutarı yalnız amount ile gönderin |
Sepet toplamı amount'a eşit değil | 400 VALIDATION_ERROR | Kalemlerin price toplamını amount'a eşitleyin |
Idempotency-Key yok | 400 payment.operation.idempotency_key_required | Her deneme için bir anahtar gönderin |
| Yöntem tanınmıyor ya da bu uçta kullanılamıyor | 400 payment.method.unknown, payment.method.not_supported | GET /payments/methods listesindeki bir yöntemi kullanın |
| Bloktaki alanlar sağlayıcının tanımına uymuyor | 400 payment.method.block_invalid | details.field alanını düzeltin |
| Yöntem panelde (form ayarlarında) kapalı | 422 payment.method.disabled | Yöntemi panelde açın; açık yöntemleri GET /payments/methods ile okuyun |
BUYER yönteminde birden fazla sağlayıcı bağlı, seçim yok | 400 payment.provider.required | <blok>.providerCode gönderin |
PLATFORM yönteminde bağlı sağlayıcıların hiçbiri ödemeyi karşılamıyor | 422 payment.provider.none_eligible | details.candidates içindeki sonuçlara bakın; daha sonra tekrar deneyin ya da providerCode ile sağlayıcı seçin |
| Seçilen sağlayıcı kullanılamıyor | 422 payment.provider.not_available | Listedeki bir sağlayıcıyı seçin |
| Yöntem ön provizyonu desteklemiyor | 422 payment.preauth.unsupported_for_method | preauth olmadan gönderin |
| Kimlik, imza ya da ürün yetkisi hatası | 401, 403, 503 | Bkz. Kart — 2D › Hatalar |
| Aynı anahtar, farklı istek | 409 payment.idempotency.conflict | Yeni deneme için yeni anahtar kullanın |
| Aynı anahtarla istek sürüyor | 429 payment.idempotency.processing | Kısa süre sonra aynı anahtarla tekrar deneyin |
| Sağlayıcı ya da risk reddi | 400, ödeme FAILED | Reddi gösterin; yeni deneme için yeni anahtar kullanın |
| Sonuç kesinleşmedi | 202 PAYMENT_PENDING_RECONCILIATION | Yeni ödeme açmayın; webhook'u bekleyin |
Yönteme özgü hatalar yöntem sayfalarındadır.
Hata kodları
Aşağıdaki kodlar ödeme yöntemi, sağlayıcı seçimi ve aksiyon uçlarına özgüdür.
| Kod | HTTP | Anlamı ve ne yapmalı |
|---|---|---|
payment.method.unknown | 400 | paymentMethod tanınmıyor. Geçerli bir yöntem kodu gönderin |
payment.method.not_supported | 400 | Yöntem kodu tanınıyor ama bu işlemde kullanılamıyor. GET /payments/methods listesindeki yöntemleri kullanın |
payment.method.block_invalid | 400 | Yöntem bloğu sağlayıcının inputFields tanımına uymuyor. Sorunlu alan details.field, sebep details.reason, bütün ihlaller details.errors[] içindedir |
payment.method.disabled | 422 | Yöntem işletmenin form ayarlarında kapalı. Panelde kapatılan yöntem formda, listede ve bu uçta kapalıdır; ödeme başlamadan reddedilir |
payment.method.wallet_bridge_not_available | 422 | Seçilen cüzdanın doğrulama akışı bu uçta desteklenmiyor; bu uç cüzdan onayını tek seferlik kodla alır |
payment.method.customer_identity_conflict | 400 | Cüzdanla ödemede alıcı customerId alanıyla tanımlanır. metadata.customerId bu alan olmadan gönderilemez ve ondan farklı olamaz |
payment.provider.required | 400 | Bu yöntemde sağlayıcıyı alıcı seçer (BUYER) ve birden fazla sağlayıcı bağlı. <blok>.providerCode ile seçin; bağlı kodlar details.boundProviderCodes içindedir. Ayrıntı: Hata Yönetimi |
payment.provider.none_eligible | 422 | PLATFORM yönteminde providerCode gönderilmedi ve bağlı sağlayıcıların hiçbiri bu ödemeyi karşılamıyor; ödeme başlatılmadı, tutar çekilmedi. Ayrıntı: Hata Yönetimi |
payment.provider.not_available | 422 | Seçilen sağlayıcı bu yöntem için kullanılamıyor. Ödeme başka sağlayıcıya yönlendirilmez |
payment.provider.pin_violation | 500 | Ödeme şu anda tamamlanamıyor; para çekilmedi. Daha sonra tekrar deneyin |
payment.operation.idempotency_key_required | 400 | Idempotency-Key başlığı bu uçta zorunlu |
payment.action.not_found | 404 | Ödeme ya da aksiyon bulunamadı (başka hesaba ait ödeme dahil). paymentId ve action.id değerlerini kontrol edin |
payment.action.replaced | 409 | Aksiyonun yerine resend ile yenisi açıldı. details.replacedByActionId aksiyonuyla ve son gönderilen kodla devam edin |
payment.action.expired | 409 | Aksiyonun süresi doldu. Yeni bir ödeme başlatın |
payment.action.in_progress | 409 | Aynı aksiyon için başka bir istek işleniyor. Birkaç saniye sonra aynı isteği tekrarlayın; kaydedilmiş sonuç döner |
payment.action.closed | 409 | Aksiyon kapanmış; üzerinde işlem yapılamaz |
payment.action.payment_not_pending | 409 | Ödeme artık bu adımı beklemiyor. Durumu GET /payments/:id ile okuyun |
payment.action.otp_required | 400 | Kod gönderilmedi ya da biçimi geçersiz (yalnız rakam). Deneme hakkı düşmez |
payment.action.consent_required | 422 | Sözleşme onayı gerekli: consentAccepted: true gönderin. Deneme hakkı düşmez |
payment.action.input_invalid | 400 | fields, action.input.fields tanımına uymuyor; sorunlu alan details.field içindedir. Deneme hakkı düşmez |
payment.action.input_rejected | 422 | Sağlayıcı kodu reddetti. Aksiyon açık kalır; kalan hak details.attemptsRemaining içindedir. Bu bir ödeme yanıtıdır: data ödemeyi ve açık action'ı taşır |
payment.action.attempts_exhausted | 400 | Deneme hakkı bitti; ödeme FAILED oldu. Bu bir ödeme yanıtıdır |
payment.action.confirm_not_applicable | 409 | Bu aksiyon confirm ile tamamlanmaz; alıcı action.redirect.url adresine gider, sonuç dönüşte doğrulanır ve webhook ile bildirilir |
payment.action.resend_not_supported | 422 | Bu yöntemde kod yeniden gönderilemez |
payment.action.resend_too_soon | 429 | Önceki gönderimin üzerinden yeterli süre geçmedi. details.retryAfterSeconds saniye bekleyin |
payment.action.resend_limit_reached | 422 | Bu ödeme için yeniden gönderme hakkı doldu. Mevcut kodla devam edin ya da yeni ödeme başlatın |
payment.action.resend_failed | 502 | Yeni kod şu anda gönderilemedi; mevcut aksiyon açık ve kod geçerli olabilir. Tekrar deneyin |
payment.action.auth_ambiguous | 400 | İstek hem API imzası hem checkout token'ı taşıyor. Sunucunuzdan yalnız imzayla çağırın |
Sonraki adımlar
- Yöntemleri Listeleme — açık yöntemler, sağlayıcı seçimi ve yöntem alanları
- Kart — bu uçtan 2D (Kart — 2D) ve 3D Secure (Kart — 3D Secure) kart ödemesi
- Cüzdanla Öde — cüzdan sağlayıcıları ve işletmenin cüzdan programı
- Faturana Yansıt — telefon faturasıyla ödeme
- Senetle Öde — elektronik senetle vadeli tahsilat
- Ön Provizyon, Capture & İptal — bloke ve sonradan çekim
- Webhook'lar — ödeme olayları