GET /plugin-api/packets/get ✓ CanlıAction ve iframe etkileşimleri yalnızca packetId taşır; paketin DOLU order'ını (ürünler, müşteri, adres, toplam ve ödeme kırılımı payments[]) bu uçtan çekersiniz. Standart desen: etkileşim bir id taşır, veri API'den okunur.
← API Uçları · ortak kurallar (base, auth, hata zarfı) orada.
GET {RESTOMENUM_BASE}/plugin-api/packets/get?packetId=<id>
Authorization: Bearer <apiKey> // kurulumdaki (OAuth exchange) install API key{RESTOMENUM_BASE}): ortama göre — Sandbox https://sandbox.plugins.restomenum.app, Production https://plugins.restomenum.app (tüm liste: API Uçları).Authorization: Bearer <apiKey> — kurulumda OAuth token exchange'te aldığın apiKey.orders:read zorunlu (yoksa plugin.scope.denied).data, webhook packet.created ile aynı kanonik alan ailesini taşır (envelope olmadan); alanların tam açıklaması o referansta. Canlı API yanıtında iki incelik var (aşağıda).
{ "success": true, "data": {
"packetId": "1780950756501",
"docNo": 9,
"entegrasyon": "packet", // sipariş kanalı — STRING kod (packet | yemeksepeti | getir | trendyol …)
"total": 27.8, "paid": 0, "totalDiscount": 0, "paymentNote": "nakit",
"orders": [
{ "id": "1780950755436-de37", "title": "Cortado", "quantity": 1,
// seçilen seçenekler — NESNE dizisi { id, title, price } (eskiden düz ad dizisi).
// price katalogtan gelir; ücretliyse lineTotalDecimal'a platformca dahildir (elle ekleme).
"options": [ { "id": "1693060234511", "title": "Az şekerli", "price": 0 } ],
"extraDecimal": 0, "discountDecimal": 0, "note": "", "lineTotalDecimal": 13.9 }
],
"payments": [], // ödeme kırılımı — bu pakette tahsilat yok (paid: 0). Satır şeması aşağıda.
"customer": { // ⚠️ customers:read + consent ile DOLU gelir; yoksa PII alanları kırpılır
"id": "123456", "name": "Ahmet Bayrak", "phone": "123456", "call": "123456",
"address": "Adres", "addressDescription": null, "region": null
}
} }entegrasyon canlı API'de bir string kanal kodudur ("packet", "yemeksepeti" …) — obje değil. orderCode, isScheduled, scheduledDate, note ve orders[].product opsiyoneldir: yalnız ilgili durumda (entegrasyon / ileri tarihli sipariş / not) gelir, manuel pakette yanıtta yer almaz. Eksikliğe dayanıklı parse et.// entegrasyon siparişi + scheduled örnek (ek alanlar):
{
"orderCode": "A12", // platform sipariş kodu (yemeksepeti/getir/trendyol)
"isScheduled": true, "scheduledDate": 1780999999000, // ileri tarihli teslim (epoch ms)
"note": "Zili çalma" // müşteri notu (varsa)
// orders[].product: { title, … } // bazı kanallarda tam ürün objesi de eklenir
}{
"type": "takeaway", // SATIŞ düzeyi tüketim biçimi — null = "bilinmiyor"
"orders": [{
"id": "kiosk-9f2c",
"lineId": "kiosk-9f2c", // = id (yazma/okuma simetrisi); eski satırlarda null
"metadata": [ // DİZİ; hiç yazılmadıysa null
{ "key": "tseRef", "value": "TSE-9911", "by": "hellokiosk" }, // by = YAZAR (platform damgalar)
{ "key": "loyalty", "value": "L-2", "by": "sadakat" } // başka eklentinin öğesi — kendininkini by ile ayıkla
]
}],
"payments": [{
"lineId": "pay-7c31", // KALICI satır kimliği (yoksa null) — methodId ile KARIŞTIRMA
"methodId": "m-cash", // ödeme YÖNTEMİ id'si
"metadata": [ { "key": "tseTx", "value": "77", "by": "fiskaly" } ] // yoksa null
}]
}lineId + metadata, satış düzeyinde type döner. Üçü de eski kayıtlarda null'dır ("bilinmiyor" — kimlik/biçim uydurulmaz); payments[].id'ye fallback yapılmaz. Aynı alanlar tables/get, packet.created ve kapanış gate'inde de gelir — hepsi aynı modelden üretilir. Alanları göndermeyen eklentiler etkilenmez.Bir sipariş satırının seçilmiş seçenekleri tipli nesne dizisidir. Aynı şekil tüm okuma yüzeylerinde geçerlidir: packets/get, tables/get, packet.* / table.* olayları (created/updated/closed/deleted/reopened/closed_deleted), packet.cancelled, customer.order_added, hook includeData gövdesi, callback servisi ve iptal listesi cancels[].
"options": [
{ "id": "1693060234600", "title": "Ekstra Peynir", "price": 15 }
]
// id → katalogdaki seçenek kimliği (products/get → options[].choices[].id)
// title → seçenek adı
// price → katalogtan okunan birim fiyat; YAZARKEN BEYAN EDİLEMEZ, lineTotalDecimal'a platform dahil eder
//
// Yazarken üç biçimden biriyle beyan edersin: { id } | { title } | "ad" (eski biçim).
// Okurken her zaman üç alan birden döner.["Ekstra Peynir"]). Yalnız ada ihtiyacın varsa options.map(o => o.title) yaz. price satır toplamına platformca dahildir — lineTotalDecimal üzerine ayrıca ekleme.{ id }, { title } ya da düz string ile beyan edersin; fiyat beyan edilemez (şema reddeder, katalogtan okunur). Ayrıntı: packets/create.Bu üç alan dokümandan ham geçiyordu (lineTotalDecimal ve vatRate normalize edilirken): sözleşme tip garantisi vermiyordu ve alan eksikse payload'dan sessizce düşüyordu — "alan gelmedi" ile "değer yok" ayırt edilemiyordu. ⏳ Artık her zaman sonlu bir sayı gelir.
| Girdi | extraDecimal / discountDecimal | quantity |
|---|---|---|
| "10" · "10,50" | ayrıştırılır → 10 · 10.5 (virgül ondalık ayırıcı) | |
| "" · çözülemeyen | 0 | 1 |
| alan yok | 0 | 1 |
| açık 0 | 0 | 0 (korunur) |
quantity neden 1'e düşüyor? Aynı satırın lineTotalDecimal'ı eksik adedi 1 kabul ederek hesaplanıyor; 0 deseydik gövde kendi kendini yalanlardı ({ quantity: 0, lineTotalDecimal: 100 }). Yuvarlama yapılmaz — quantity para değildir, kilo bazlı satır ikiden fazla ondalık taşıyabilir.Number("") → NaN dalı artık hiç doğmuyor. Ölçüm: dört üretim tenant'ında 1196 satır tarandı, tamamı zaten sayıydı — bu bir veri düzeltmesi değil, sözleşme garantisidir. (Sandbox'ta yayında, production'a çıkmadı.)Satır tutarı iki biçimde gelir: lineTotalDecimal (ondalık, değişmedi) ve amounts (tamsayı minor unit bileşen kırılımı). Para birimi belgede bir kez durur.
{
"currency": "TRY", // ISO-4217 — çözülemezse alan HİÇ gelmez
"amountExponent": 2, // YALNIZ amounts.* için (TRY → kuruş)
"total": 27.8, "paid": 0, // ← ONDALIK, değişmedi (üssü BUNLARA uygulama)
"orders": [{
"lineTotalDecimal": 13.9, // ← ONDALIK
"vatRate": 10,
"amounts": { // ← TAMSAYI minor unit (kuruş)
"base": 1390, "options": 0, "extra": 0, "discount": 0, "timer": 0,
"gross": 1390, "net": 1264, "vat": 126
}
}]
}amountExponent yalnız amounts.* içindir. total, paid, lineTotalDecimal, options[].price, payments[].amount ondalıktır — üssü onlara uygularsan 100 kat sapma alırsın. Garantiler, karışık KDV kovaları (perVat) ve geri düşüş kuralları: Tutarlar (amounts).payments[], paketin ödeme satırlarını taşır ve orders:read ile gelir. Aynı satır şekli packets/get, tables/get ve packet.created yüzeylerinde birebir aynıdır. İç alanlar (created = işlemi yapan personel, log, description) gönderilmez.
// payments[] satırı — allowlist (packets/get · tables/get · packet.created BİREBİR AYNI)
{
"methodId": string | null, // tenant'ın ödeme yöntemi id'si; tanımlı yönteme bağlı değilse null
"title": string, // yöntemin başlığı (tenant tanımı) — gösterim için
"amount": number, // satır tutarı
"cash": boolean, // yöntem NAKİT mi → CASH / NON_CASH ayrımı YALNIZ buradan okunur
"cashDeclared": boolean, // cash BEYAN mı, yoksa platformun güvenli varsayımı mı
"isDiscount": boolean // true → indirim satırı (tahsilat DEĞİL), satır listede KALIR
}| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
| methodId | string | null | ✓ | Tenant'ın ödeme yöntemi id'si — geçerli id'ler payment-methods/list'ten gelir. Satır tanımlı bir yönteme bağlı değilse null (satırın kendi uuid'si sızdırılmaz). |
| title | string | ✓ | Yöntemin tenant tanımındaki başlığı (örn. "nakit"). Gösterim içindir. |
| amount | number | ✓ | Satır tutarı. Tüm satırların toplamı paid'e eşittir (indirim satırları dahil). |
| cash | boolean | ✓ | Yöntem nakit mi. Mali CASH/NON_CASH ayrımının tek doğru kaynağı budur; tenant tanımında işaretli değilse false gelir. |
| cashDeclared | boolean | ✓ | cash bir beyan mı, yoksa platformun güvenli varsayımı mı? false → yöntem kaydında nakitlik alanı hiç doğmamış. Mali damgalamada bu ayrım kritiktir — bkz. aşağıdaki uyarı. |
| isDiscount | boolean | ✓ | true → satır bir indirimdir, tahsilat değildir. Satır listeden düşürülmez; totalDiscount bu satırlardan türetilir. |
cash bayrağından oku — methodId veya title METNİNDEN çıkarma. Id'ler tenant'a özeldir ("29-cash" gibi bir id nakit olmayabilir, "kart" adlı bir yöntem nakit işaretli olabilir). Ayrıntı için payment-methods/list.cashDeclared:false ise cash bir varsayımdır. Yöntem kaydında nakitlik alanı hiç doğmamıştır (genelde kiracı açılışında oluşan varsayılan yöntemler). Almanya'da ödeme tipi (Bar/Unbar) imzalanan fişin güvence altına alınan verisidir (ZAHLART_TYP): cashDeclared:false görürsen varsayıma dayalı sınıflandırmayı damgalama, kiracıdan beyan iste.methodId taşıyor (teslimat entegrasyonlarının ürettiği sözde-yöntemler). O satırlarda join edecek hedef YOKTUR → nakitlik bilgisini satırdan oku.// Satır kimliği + korelasyon alanı — aynı satırda döner
{
"lineId": string | null, // KALICI satır kimliği; eski/panel satırlarında null (id'ye FALLBACK YOK)
"metadata": [ { key, value, by } ] | null // opak korelasyon DİZİSİ; by = yazar (platform damgalar)
}lineId ≠ methodId. lineId satırın kalıcı kimliğidir; methodId ödeme yönteminin id'sidir. Panel/yerli akışta veya bu sürümden önce yazılmış satırlarda lineId ve metadata null döner ve yazmadaki payments[].id'ye fallback yapılmaz — o alan yöntem id'si de olabildiği için iki farklı satırı aynı kimlikle gösterirdi. Kimlik uydurmak yerine "bilinmiyor" denir. Kurallar: Satır kimliği & metadata.cancelPayments[] — iptal edilen tahsilatlar. payments[] ile birebir aynı şekil (yeni bir tip öğrenmene gerek yok). Satır void'i (cancels) yayınlanırken ödeme void'inin yayınlanmaması doğrudan bir asimetriydi: iptal edilmiş bir tahsilat tüketiciye hiç görünmüyor, defterdeki "ödenmiş" tutar POS'takinden sapıyordu. ⚠️ paid aktif ödemelerin toplamıdır — bu liste ona dahil değildir. (Sandbox'ta canlı, production'a dağıtılmadı.)sum(amount) === paid korunur. Mali toplamda isDiscount:true satırlarını tahsilat gibi sayma; ama listeden atarsan toplam paid'i tutmaz.customer alanları webhook ile aynı kuralla kırpılır: customers:read yoksa PII alanları (name, phone, address, email, tckn, vergino) silinir; id vb. kalır.| Durum | Yanıt |
|---|---|
| Paket yok | { success:false, message:"plugin.packets.notFound" } |
| Scope yok | { success:false, message:"plugin.scope.denied" } |
// action-hook (/api/action) ya da iframe (/api/send) içinde: etkileşim yalnız packetId taşır → dolu paketi çek.
const id = envlp.target.id; // packet.created ile aynı packetId (target.type: packet)
const r = await fetch(`${RESTOMENUM_BASE}/plugin-api/packets/get?packetId=${id}`, {
headers: { Authorization: `Bearer ${apiKey}` }, // kurulumdaki install API key
});
const { success, data, message } = await r.json();
if (!success) throw new Error(message); // plugin.packets.notFound | plugin.scope.denied
// data.orders / data.customer / data.total … → kurye/hedef sisteme ilet