Ödeme Detayı — GET /plugin-api/payments/{paymentId} ⏳ Yakında

Sağlayıcının CİHAZDAKİ uygulaması, kasadan aldığı paymentId ile tahsil edilecek tutarı ve (TR'de) kalem dökümünü buradan çeker. Kimlik cihaz oturum JWT'sidir, install API key değil. Tutarı çekmek aynı zamanda ACK'tir: deneme ACCEPTED'a geçer ve 60 saniyelik servis penceresi başlar.

← API Uçları · Cihaz kaydı: connectors/* · Sonucu bildir: payments/{id}/result · Uygulamanız nasıl çağrılır: cihaz taşıması.

⚠️ Bu uç PRODUCTION'a HENÜZ DAĞITILMADI. Yalnız devortamında var; production fonksiyonu daha eski bir sürümden çalışıyor ve bu yolu tanımıyor. Denenebilecek tek adres yukarıdaki dev adresidir — prod adresini bilerek yazmadık.

⚠️ Prod'da deneyip 401 alırsan bunu "uç var, yetkim yok" diye OKUMA. Bu yüzeyde tanınmayan bir yol da kimlik katmanına düşer ve 401 döner — yani 401, "uç yok"un da cevabıdır. Prod'a dağıtıldığında bu sayfa adresiyle birlikte güncellenecek.

Ölçüm kapsamı: gövdeler dev'de deploy edilmiş uca gerçek HTTPS çağrılarıyla yakalandı (33/33 uçtan uca; gerçek EC anahtar çifti, gerçek DER imza — hiçbir adım simüle edilmedi).

İstek

GET https://plugins-3y3x7nqe5a-ew.a.run.app/plugin-api/payments/{paymentId}
Authorization: Bearer <CİHAZ OTURUM JWT>     // install API key DEĞİL
Kimlik: CİHAZ OTURUM JWT'si — install API key DEĞİL. Token /v1/connectors/session çıktısıdır ve zincir şudur: kayıt kodu → cihaz anahtarı → DER imza → 5 dk ömürlü JWT. Yani bu ucu çağıran taraf eklentinin bulutu değil, restorandaki cihazdır; eklenti API anahtarıyla çağırmayı deneme.

Yanıt

{ "success": true, "data": {
  "SaleData": { "SaleReferenceID": "9001" },
  "PaymentTransaction": {
    "AmountsReq": { "Currency": "TRY", "RequestedAmount": 240 },
    "SaleItem": [
      { "ItemID": 0, "ProductCode": "e2e-prod-1", "ProductLabel": "E2E Adana",
        "Quantity": 2, "UnitPrice": 120, "ItemAmount": 240, "TaxCode": "10",
        "RestomenumExt": { "CategoryId": "e2e-cat", "LineId": "l1" } }
    ]
  },
  "RestomenumExt": {
    "PaymentId": "pay_f462…", "State": "ACCEPTED", "Market": "TR",
    "ExpiresAt": 1788626365044, "ItemsScope": "fullSale", "SaleTotalAmount": 240
  }
} }

GET = ACK — çekmeden terminali sürme

Tutarı çektiğin an deneme ACCEPTED'a geçer. Bu, platformun "komut cihaza ulaştı" kanıtıdır — ayrı bir onay mesajı yok. GET yapmadan terminali sürme: aksi hâlde platform komutun ulaşmadığını sanarken kart çekilmiş olur.

60 saniyelik servis penceresi

İlk GET'ten sonra tutar yalnız 60 saniye verilir; sonrasında 409 plugin.payment.amountWindowClosed.
{ "success": false, "message": "plugin.payment.amountWindowClosed", "status": 409 }
  • Pencere içinde tekrar çekmek idempotenttir — ağ hatasında yeniden deneyebilirsin.
  • ⚠️ Kalıcı kuyruktan ESKİ bir isteği yeniden işlersen tutarı ALAMAZSIN. Bu kasıtlıdır: pencere, saatler önce kuyruğa girmiş bir işin bugün kart çekmesini engeller. Kuyruğunda bekleyen bir iş varsa önce yaşını kontrol et, sonra terminale gitme kararı ver.

Tutarlar ONDALIK — kesme yasak

Tutarlar ondalık JSON sayısıdır (240, 99.99); Exponent alanı yoktur ve minor-unit tam sayı değildir.

İçeri alırken Math.round(x * 100) kullan — KESME (truncate) YASAK. Kayan noktada 8.29 * 100 gibi değerler 828.999… durur; kesme 1 kuruş eksik yazar. Ölçülen kaybettiren değerler: 8.29 · 4.35 · 1.15 · 19.99 · 0.29 · 0.57 · 0.58 · 16.08.

Kural: tel formatı ondalık, aritmetik tam sayı kuruş. Dönüşümü yalnız sınırda ve yuvarlayarak yap; para hesabını double üzerinde sürdürme.

TR ve EU aynı gövdeyi döndürmez

  • TR: SaleItem vardır (mali kalem dökümü zorunlu).
  • EU: SaleItem HİÇ YOKTUR.
  • ItemsScope: "fullSale" → kalemler tüm satışın dökümüdür. RequestedAmount ise kısmi olabilir (TR'de artımlı ödeme normaldir) → ikisi eşit olmayabilir, bunu bir tutarsızlık sanma. SaleTotalAmount kalemlerin toplamıdır.
  • ProductCode ve RestomenumExt.CategoryId kararlı katalog kimlikleridir — cihazdaki departman/grup eşlemesini ADA göre kurma, ProductLabel değişebilir.

Hatalar

HTTPmessageAnlamı
401plugin.connector.unauthorizedCihaz oturum token'ı geçersiz/süresi dolmuş (5 dk).
404plugin.payment.notFoundİKİ anlama gelir — aşağıdaki nota bak.
409plugin.payment.expiredDeneme süresi doldu.
409plugin.payment.notActionableDeneme bu durumda işlenemez.
409plugin.payment.amountWindowClosed60 sn servis penceresi kapandı.
409plugin.payment.saleItemsUnavailableKalem dökümü üretilemedi.
429plugin.rateLimitedHız sınırı.
404 İKİ anlama gelir ve ayrım bilinçli olarak yapılmaz: "böyle bir paymentId yok" ve "bu ödeme senin cihazının değil". Ayırmak, başka bir sağlayıcının ödeme kimliklerini taramaya izin verirdi. Kendi kodunda 404'ü "yetkim yok" olarak da oku — "kayıt silinmiş" varsayma.
Sıradaki adım: sonucu bildirmek. Tahsilatı yaptıktan sonra sonucu POST /plugin-api/payments/{paymentId}/result ile bildirirsin — aynı cihaz oturum JWT'si ile. Eski payments/status ucu duruyor ve değişmedi, ama yerel akışta bildiren taraf cihaz olduğu için bu yeni yolu kullan.