Payment Orchestrator
Linkle Ödeme
Linkleri Yönetme

Linkleri Yönetme

Oluşturduğunuz linkleri bu sayfadaki uçlarla yönetirsiniz. Bütün uçlar Link Oluşturma sayfasında anlatılan imzalı istek ile çağrılır ve anahtarınızın ilgili payment-link:* yetkisini ister. Bir anahtar yalnız kendi ortamındaki (TEST ya da LIVE) linkleri görür; başka bir organizasyonun ya da diğer ortamın linki 404 döner. Aynı işlemleri panelden de yapabilirsiniz.

Tüm tutarlar minor-unit (kuruş) cinsinden tam sayıdır: "collectedAmountMinor": 150000 = ₺1.500,00.

YöntemYolYetkiIdempotency-Key
GET/api/v1/payments/linkspayment-link:view—
GET/api/v1/payments/links/:idpayment-link:view—
PATCH/api/v1/payments/links/:idpayment-link:manageİsteğe bağlı
POST/api/v1/payments/links/:id/pause · /resume · /deactivatepayment-link:manageİsteğe bağlı
POST/api/v1/payments/links/:id/sendpayment-link:sendZorunlu
GET/api/v1/payments/links/:id/qrpayment-link:view—
GET/api/v1/payments/links/:id/attemptspayment-link:view—
GET/api/v1/payments/links/:id/paymentspayment-link:view—

Node.js örnekleri Link Oluşturma sayfasındaki signedHeaders yardımcısını kullanır. cURL örnekleri aynı imzalama adımlarının kabuk fonksiyonu hâlini kullanır:

# lunixi-sign.sh — OpenSSL 3.0+ gerekir.
# Kullanım: source lunixi-sign.sh
#           lunixi_sign GET  "/api/v1/payments/links?limit=25"
#           lunixi_sign POST "/api/v1/payments/links/<id>/pause" "$BODY"
LUNIXI_KEY_ID="mk_test_sk_..."
LUNIXI_KEY_FILE="lunixi-signing.key"
 
lunixi_sign() {
  local method="$1" req_path="$2" body="${3-}"
  DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
  NONCE=$(openssl rand -hex 16)
  if [ -n "$body" ]; then
    DIGEST="SHA-256=$(printf '%s' "$body" | openssl dgst -sha256 -binary | base64)"
    printf '%s\n%s\nX-Date:%s\nX-Nonce:%s\nDigest:%s' "$method" "$req_path" "$DATE" "$NONCE" "$DIGEST" > canonical.txt
  else
    DIGEST=""
    printf '%s\n%s\nX-Date:%s\nX-Nonce:%s' "$method" "$req_path" "$DATE" "$NONCE" > canonical.txt
  fi
  SIGNATURE=$(openssl pkeyutl -sign -inkey "$LUNIXI_KEY_FILE" -rawin -in canonical.txt | base64 | tr -d '\n')
}

Listeleme

GET /api/v1/payments/links linklerinizi en yeniden eskiye, cursor tabanlı sayfalar hâlinde döner.

Sorgu parametresiTipAçıklama
limitintegerSayfa başına kayıt, 1–100. Varsayılan 25.
cursorstringÖnceki yanıttaki pageInfo.nextCursor. İlk sayfada gönderilmez.
includeTotalbooleantrue ise pageInfo.totalCount doldurulur. Daha yavaştır; gerekmedikçe göndermeyin.
statestringVirgülle ayrılmış durumlar, ör. ACTIVE,PAUSED.
usagestringVirgülle ayrılmış: SINGLE_USE,MULTI_USE.
amountModestringVirgülle ayrılmış: FIXED,OPEN,ITEMIZED.
tagstringBu etiketi taşıyan linkler.
branchCodestringBu şube koduna sahip linkler.
createdByIdstringBu kimliğin oluşturduğu linkler (API ile oluşturulanlarda anahtar kimliği).
querystringKısa kodla tam eşleşme ya da başlık / reference başıyla arama. Kod büyük-küçük harf, tire ve boşluk fark etmeden eşleşir.
createdFrom, createdTostring (ISO 8601)Oluşturulma aralığı; createdFrom dahil, createdTo hariç.
environmentstringSonuç her zaman anahtarınızın ortamıyla sınırlıdır.
source lunixi-sign.sh
REQ_PATH="/api/v1/payments/links?limit=25&state=ACTIVE,PAUSED"
lunixi_sign GET "$REQ_PATH"
 
curl "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" \
  -H "X-Date: $DATE" \
  -H "X-Nonce: $NONCE" \
  -H "X-Signature: $SIGNATURE"

Yanıt

pageInfo, data'nın yanındadır; liste data.items içindedir.

{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "items": [
      {
        "id": "5f0c1d2e-8a4b-4c6d-9e7f-1a2b3c4d5e6f",
        "shortCode": "7KQ2M9XAPT",
        "url": "https://pay.lunixi.com/7KQ2M9XAPT",
        "organizationId": "b1d2c3e4-…",
        "environment": "TEST",
        "state": "ACTIVE",
        "usage": "SINGLE_USE",
        "amountMode": "FIXED",
        "currency": "TRY",
        "amountMinor": 150000,
        "title": "Kasım danışmanlık bedeli",
        "reference": "INV-2026-0042",
        "tags": [],
        "paidCount": 0,
        "collectedAmountMinor": 0,
        "expiresAt": "2026-10-31T20:59:59.000Z",
        "createdByType": "API_KEY",
        "createdById": "mk_test_sk_…",
        "createdAt": "2026-09-25T09:00:00.000Z",
        "version": 1,
        "rowVersion": 1
      }
    ]
  },
  "pageInfo": { "hasMore": false, "nextCursor": null, "totalCount": null },
  "statusCode": 200,
  "requestId": "req_7f3d9c1a4b2e"
}

Liste satırı özettir; amountMinor yalnız FIXED linklerde doludur. Tam kayıt için GET /api/v1/payments/links/:id çağırın.

Tek link

GET /api/v1/payments/links/:id linkin tam kaydını döner: bütün alanlar, recipient ve prefill dahil, sayaçlar (counters), stok durumu (availability) ve kilit bayrakları. Yanıt şekli oluşturma yanıtıyla aynıdır — bkz. Link Oluşturma › Yanıt.

Güncelleme

PATCH /api/v1/payments/links/:id linkin tanımını değiştirir ve yeni bir sürüm (version) üretir. Süren ödemeler başladıkları sürümün tutar ve kurallarıyla tamamlanır.

KuralAyrıntı
expectedRowVersion zorunluSon okuduğunuz rowVersion. Link arada değiştiyse 409 payment_link.link.version_conflict döner: linki yeniden okuyun, değişikliğinizi yeniden uygulayın.
Yalnız gönderdiğiniz alanlar değişirGövdedeki her anahtar değişecek bir alandır; göndermediğiniz alanlar olduğu gibi kalır.
null temizlerör. "expiresAt": null linki süresiz yapar, "successRedirectUrl": null başarı sonrası yönlendirmeyi kaldırır.
Nesne ve diziler bütün olarak değişiritems, buyerFields, customFields, recipient, prefill, verification, reminders, checkout, tags, metadata kısmi birleştirilmez; alanın yeni hâlinin tamamını gönderin. Mevcut bir kalemin itemKey'i değiştirilemez.
Değişmez alanlarusage, amountMode, currency → 422 payment_link.link.immutable_field
Tutar kilidiSüren bir ödeme varken ya da link ödeme almışsa (amountLocked: true) tutar alanları değiştirilemez: amountMinor, minAmountMinor, maxAmountMinor, suggestedAmountsMinor, quantityEnabled, minQuantity, maxQuantity, items, capacity → 409 payment_link.link.amount_locked. İstisna: capacity ve kalemlerin capacity değeri artırılabilir (satılan ve süren ödemelerin tuttuğu birimden az olamaz). Kalem kapasitesini artırmak için items dizisini yalnız capacity değerleri değişmiş olarak gönderin.
Kaldırılmış linkTAKEN_DOWN linkte 409 payment_link.link.taken_down

Başlık, açıklama, bitiş zamanı, alıcı alanları ve atıf alanları gibi tutar dışı alanlar tutar kilidine tabi değildir. Başarılı güncelleme payment.link.updated yayınlar.

source lunixi-sign.sh
LINK_ID="5f0c1d2e-8a4b-4c6d-9e7f-1a2b3c4d5e6f"
REQ_PATH="/api/v1/payments/links/$LINK_ID"
BODY='{"expectedRowVersion":1,"title":"Kasım danışmanlık bedeli (revize)","expiresAt":"2026-11-15T20:59:59.000Z"}'
lunixi_sign PATCH "$REQ_PATH" "$BODY"
 
curl -X PATCH "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "Content-Type: application/json" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" \
  -H "X-Date: $DATE" \
  -H "X-Nonce: $NONCE" \
  -H "Digest: $DIGEST" \
  -H "X-Signature: $SIGNATURE" \
  --data-raw "$BODY"

Duraklatma, devam ettirme ve iptal

POST /api/v1/payments/links/:id/pause, /resume ve /deactivate linkin durumunu değiştirir ve güncel linki döner.

AlanTipZorunluAçıklama
expectedRowVersionintegerHayırGönderirseniz linkin rowVersion'ıyla eşleşmelidir (409 payment_link.link.version_conflict). Göndermezseniz ya da 0 gönderirseniz kontrol yapılmaz.
reasonstringHayırEn fazla 500 karakter; linkin işlem geçmişine yazılır, alıcıya gösterilmez.
İşlemGeçişEvent
pauseACTIVE → PAUSEDpayment.link.paused
resumePAUSED → ACTIVE — expiresAt gelecekte olmalıpayment.link.resumed
deactivateACTIVE ya da PAUSED → DEACTIVATED — kalıcıdırpayment.link.deactivated

Geçersiz geçiş (ör. COMPLETED bir linki duraklatmak) 409 payment_link.link.invalid_transition döner.

⚠️

Duraklatma ve iptal, o anda süren bir ödemeyi durdurmaz. Alıcı ödeme formundaysa ödeme tamamlanabilir; o durumda payment.captured yine gelir ve linkin sayaçları güncellenir. Siparişi her zaman payment.captured ile değerlendirin.

source lunixi-sign.sh
REQ_PATH="/api/v1/payments/links/$LINK_ID/pause"
BODY='{"expectedRowVersion":2,"reason":"Stok sayımı"}'
lunixi_sign POST "$REQ_PATH" "$BODY"
 
curl -X POST "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "Content-Type: application/json" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" -H "X-Date: $DATE" -H "X-Nonce: $NONCE" \
  -H "Digest: $DIGEST" -H "X-Signature: $SIGNATURE" \
  --data-raw "$BODY"

Gönderme

POST /api/v1/payments/links/:id/send linki Lunixi üzerinden e-posta ya da SMS ile gönderir. Idempotency-Key zorunludur: aynı anahtarla tekrar isteği yeni bir gönderim yapmaz, ilk gönderimi replayed: true ile döner; aynı anahtar farklı gövdeyle 409 payment_link.idempotency.conflict alır.

AlanTipZorunluAçıklama
channelstringEvetEMAIL | SMS
recipientEmailstringHayırBoşsa linkin recipient.email adresi kullanılır.
recipientPhonestringHayırE.164. Boşsa linkin recipient.phone numarası kullanılır.
localestringHayırİleti dili: tr | en.
{
  "status": "success",
  "code": "SUCCESS",
  "data": {
    "delivery": {
      "id": "0e8a7c55-…",
      "kind": "REQUEST",
      "channel": "EMAIL",
      "recipientMasked": "a***@example.com",
      "state": "QUEUED",
      "failureReason": null,
      "attemptId": null,
      "createdAt": "2026-09-25T09:05:00.000Z",
      "updatedAt": "2026-09-25T09:05:00.000Z"
    },
    "replayed": false
  },
  "statusCode": 200,
  "requestId": "req_…"
}

Gönderim QUEUED olarak kaydedilir ya da hemen FAILED döner. Sonraki durum değişiklikleri (SENT, DELIVERED, FAILED) panelde linkin gönderim geçmişinde görünür.

failureReasonAnlamıNe yapmalı
channel_not_availableSeçilen kanal hesabınız için henüz kullanılabilir değilLinki kendi kanalınızdan ya da QR ile paylaşın
test_mode_recipient_not_allowedTEST ortamında alıcı, organizasyonunuzun doğrulanmış bir üyesi değil (TEST'te SMS gönderilmez)Test gönderimlerini kendi ekibinizin adresine yapın
invalid_recipientAdres ya da numara geçersizAlıcı bilgisini düzeltip yeni bir Idempotency-Key ile gönderin
provider_rejectedGönderim sağlayıcısı iletiyi reddettiAlıcı bilgisini kontrol edin
suppressedAlıcı adresi gönderim engel listesindeBaşka bir kanal ya da adres kullanın
mock_deliveryGönderim simüle edildi, ileti alıcıya ulaşmadıLinki kendi kanalınızdan paylaşın
render_failed, dispatch_failedİleti hazırlanamadı ya da iletilemediYeni bir Idempotency-Key ile tekrar deneyin
  • Kaldırılmış linkte gönderim 409 payment_link.link.taken_down döner.
  • Gönderim, linkin erişim doğrulaması kilidini de açar (verificationLocked: false): alıcı çok fazla hatalı kod girdiyse yeni kod isteyebilmesi için linki yeniden gönderin.
  • Hatırlatmalar (reminders) ayrı bir çağrı gerektirmez; recipient dolu tek kullanımlık linkte tanımladığınız aralıkla gönderilir.

QR kodu

GET /api/v1/payments/links/:id/qr linkin adresini (https://pay.lunixi.com/<KOD>) içeren QR kodunu görsel olarak döner — JSON değil.

Sorgu parametresiDeğer
formatsvg (varsayılan) | png
sizePiksel, 128–2048. Varsayılan 512.

Yanıt Content-Type: image/svg+xml ya da image/png ve Cache-Control: no-store taşır. Hata durumunda standart JSON hata zarfı döner. Kaldırılmış linkte 409 payment_link.link.taken_down.

Bu bir URL QR'ıdır; TR Karekod değildir. Alıcı telefon kamerasıyla okutup ödeme sayfasını açar.

source lunixi-sign.sh
REQ_PATH="/api/v1/payments/links/$LINK_ID/qr?format=png&size=1024"
lunixi_sign GET "$REQ_PATH"
 
curl "https://api-gateway.lunixi.com$REQ_PATH" \
  -H "X-Key-Id: $LUNIXI_KEY_ID" -H "X-Date: $DATE" -H "X-Nonce: $NONCE" \
  -H "X-Signature: $SIGNATURE" \
  -o link-qr.png

Ödeme denemeleri

GET /api/v1/payments/links/:id/attempts linkte başlatılan her ödeme denemesini en yeniden eskiye döner. Parametreler: limit, cursor ve virgülle ayrılmış state.

Deneme stateAnlamı
OPENDeneme açıldı, ödeme formu hazırlanıyor
BOUNDÖdeme formu açıldı; alıcı ödüyor ya da bankanın sonucu bekleniyor
SUCCEEDEDÖdeme tahsil edildi
FAILEDÖdeme kesin olarak başarısız oldu
EXPIREDAlıcı ödemeyi süresi içinde tamamlamadı
ABANDONEDÖdeme formu hiç açılmadı
NEEDS_REVIEWSonuç otomatik uygulanamadı; Lunixi operasyon ekibi inceler

Bir deneme sürerken ayırdığı stok (tek kullanımlık linkte linkin kendisi) yalnız ödemenin kesin sonucuyla serbest bırakılır. Bankadan sonucu henüz gelmemiş bir ödeme için stok, süre dolsa bile tutulmaya devam eder; bu yüzden reservedQuantity bir süre dolu görünebilir.

AlanAçıklama
idDeneme kimliği — ödeme webhook'larında paymentLinkAttemptId
stateYukarıdaki tablo
linkVersionDenemenin bağlı olduğu link sürümü
paymentIdÖdeme kimliği (webhook'larda intentId); form açılmadıysa null
amountMinor, currency, quantityTahsil edilecek tutar ve adet
lines[]Kalemli linkte { itemKey, name, quantity, unitPriceMinor, lineTotalMinor }
buyerName, buyerEmail, buyerPhoneAlıcının girdiği bilgiler
customFields[]{ key, value } — özel alan cevapları
failureCodeBaşarısız denemede kanonik ret anahtarı, ör. card.insufficient_funds
outcomeCertaintyDEFINITIVE_FAILURE | UNKNOWN | null
reservationStateHELD (tutuluyor) | CONVERTED (satışa döndü) | RELEASED (bırakıldı)
createdAt, boundAt, finalizedAtZaman damgaları

Deneme kayıtları alıcının kişisel verilerini içerir; kendi sistemlerinizde buna göre saklayın.

Tahsilatlar

GET /api/v1/payments/links/:id/payments linkin başarılı ödemelerini iade toplamlarıyla birlikte döner. Parametreler: limit, cursor.

AlanAçıklama
attemptId, paymentIdDeneme ve ödeme kimlikleri
paymentStatusCAPTURED | PARTIALLY_REFUNDED | REFUNDED
amountMinorÖdemenin tutarı (taksit vade farkı hariç)
capturedAmountMinor, refundedAmountMinorTahsil edilen ve iade edilen tutar
currency, paidAtPara birimi ve ödeme zamanı
buyerEmailAlıcının e-postası
receiptNumberMakbuz numarası, ör. PL-20260925-7KQ2M9XAPT

İade için mevcut İade ucunu paymentId ile kullanın. İade linkin durumunu değiştirmez: tek kullanımlık link COMPLETED kalır, çok kullanımlık linkte satılan stok geri eklenmez.

Hatalar

StatusKodNe yapmalı
400INVALID_CURSORÖnceki yanıttaki pageInfo.nextCursor değerini aynen gönderin; filtreyi değiştirdiyseniz baştan başlayın
400payment_link.idempotency.key_requiredsend için Idempotency-Key gönderin
403API_INSUFFICIENT_SCOPEAnahtarınıza ilgili payment-link:* yetkisini ekleyin
404payment_link.link.not_foundLink yok, başka bir organizasyonun ya da diğer ortamın linki
409payment_link.link.version_conflictLinki yeniden okuyup güncel rowVersion ile tekrar deneyin
409payment_link.link.invalid_transitionLinkin güncel state'ine bakın; sonlanmış link yeniden açılmaz
409payment_link.link.amount_lockedTutarı değiştirmek için yeni link oluşturun
409payment_link.link.taken_downLink Lunixi tarafından kaldırıldı; değişiklik ve gönderim yapılamaz
409payment_link.idempotency.conflictFarklı bir gönderim için yeni Idempotency-Key üretin
422payment_link.link.immutable_fieldusage, amountMode, currency değişmez; yeni link oluşturun
422payment_link.validation.invaliddetails.errors listesindeki alanları düzeltin

İmza hataları (401) için: Link Oluşturma › Hatalar. 5xx yanıtlarında isteği üstel geri çekilmeyle yeniden deneyin; send çağrısını aynı Idempotency-Key ile tekrarlarsanız ikinci bir gönderim yapılmaz.

Sonraki adımlar