lineId) & metadata ✓ CanlıSipariş ve ödeme satırlarına kararlı bir kimlik (lineId) ve çağırana ait opak bir korelasyon alanı (metadata) eklendi. İkisi de opsiyoneldir; hiçbiri gönderilmezse davranış bugünküyle aynıdır — mevcut eklentiler etkilenmez. Aynı kurallar altı yazma ucunun hepsinde geçerlidir.
← API Uçları · Satışın tüketim biçimi: type (dine_in / takeaway / delivery).
packets/update-orders ve tables/update-orders sepetin tamamını değiştirir; alan gönderilmediğinde her yazımda satır kimlikleri yeniden üretilirdi. Almanya'da her satır kayıt anında TSE ile imzalandığı için "bu satır fişlendi mi?" sorusunun tek yanıtı satır kimliğidir — kimlik değişince zincir kopar. Artık kimliği çağıran taşır, platform korur. Sektör deseni aynı: Stripe line_item.id, Shopify OrderEdit satır kimliği — kimliği istemci taşır, sunucu korur.
lineId ve metadata AYNI yüzeylerde geçerlidir. Sepet kalemi ve ödeme satırı tek bir şemadan gelir, dolayısıyla iki alan da altı ucun hepsinde kabul edilir — sepet taşıyan uçta cart[].metadata, ödeme taşıyan uçta payments[].metadata. packets/create ve tables/create ikisini birden alır (hem sepet hem ödeme aynı gövdede).| Uç | cart[] | payments[] |
|---|---|---|
| POST /packets/create | lineId · metadata | lineId · metadata |
| POST /packets/update-orders | lineId · metadata | — |
| POST /packets/update-payments | — | lineId · metadata |
| POST /tables/create | lineId · metadata | lineId · metadata |
| POST /tables/update-orders | lineId · metadata | — |
| POST /tables/update-payments | — | lineId · metadata |
Kimlik korunması koşulludur. Tam değiştirmede platform, gelen sepetteki kimlikleri dokümandaki kimliklerle eşler. Beyan edilmeyen bir satır "silinmiş" sayılır — üzerindeki tüm metadata (seninki ve başka eklentilerinki) onunla birlikte gider.
{ "product": "POS-11",
"quantity": 1,
"lineId": "kiosk-a1" }Satır kimliği korunur. Başka eklentilerin (ör. fiskal sağlayıcının) bu satıra yazdığı metadata öğeleri de korunur.
{ "product": "POS-11",
"quantity": 1 }Platform yeni kimlik üretir. Eski satır ve üzerindeki tüm metadata düşer; mali zincir kopar. İstek reddedilmez (meşru satır silme de bu yola düşer) ama platform kaybı loglar.
kiosk-<sessionId>-<lineNo>) ve kendi tarafında sakla.A-Z a-z 0-9 . _ : - içerir. ⏳ Saf rakamdan oluşan kimlik reddedilir ("1", "42") — aşağıdaki kırıcı değişikliğe bak.kuver ve new kullanılamaz (büyük/küçük harf farketmez) — platform bu iki kimliği kendi üretir (kuver satırı, "yeni satır" sentinel'i).lineId belongs to a cancelled line döner (aşağı bkz.).lineId taşır; göndermezsen platform üretir (pay- önekli — önceden ödeme kaydının kimliği hiç yoktu).lineId: null döner; platform kimlik uydurmaz.POST {RESTOMENUM_BASE}/plugin-api/packets/update-orders
{
"packetId": "pkt_123",
"cart": [
{ "product": "POS-11", "quantity": 1,
"lineId": "kiosk-9f2c" }, // fişi kesilmiş satır — kimliği KORUNUR
{ "product": "POS-12", "quantity": 1 } // yeni → kimlik üretilir
]
}// 400
"Invalid lineId: kuver"
"Duplicate lineId: kiosk-9f2c"
"Invalid metadata: POS-11: <sebep>"
"metadata must be an array of {key, value}"
// 409 — iptal edilmiş (void) satırın kimliği yeniden beyan edildi
"lineId belongs to a cancelled line: kiosk-9f2c"GET {RESTOMENUM_BASE}/plugin-api/packets/get
{ "orders": [
{ "id": "kiosk-9f2c",
"lineId": "kiosk-9f2c", … } ] }payments[].id satır kimliği DEĞİLDİR. O alan ödeme yönteminin kimliğidir (nakit/kart tanımı) ve yerli akışlarda satır uuid'si de taşıyabilir — polimorfiktir, satır silme her yerde onu hedefler. Bu yüzden kalıcı kimlik ayrı lineId alanına yazıldı; id'nin anlamı değişmedi. Okuma yanıtında ödeme satırı lineId (kimlik) ve methodId (yöntem) alanlarını ayrı ayrı döner."lineId" length must be at least 8 characters long, saf rakamda "lineId" contains an invalid value) — yani hata "bu kimlik dokümanda var ama artık kabul edilmiyor" diye açıklamıyor da.pay-01H9XYZ…) tek çıkış yolu. Düzeltilirse değişiklik günlüğünden duyurulur.Canlıda bir eklenti satır kimliği olarak "1" yazdı. Sözleşme benzersizliği yalnız doküman içinde garanti eder — ama mali tüketici için lineId, "bu satır fişlendi mi?" sorusunun tek yanıtıdır: iki satış aynı kimliği taşıyınca ikisi tek satır sayılır ve ikincisi fişsiz kalır. Alt sınır bu yüzden 8'e çıktı ve saf rakam yasaklandı — "00000001" sekiz karakterdir ama iki bağımsız sayaç kaçınılmaz olarak aynı değerleri üretir, uzunluk tek başına yetmiyor.
Tam-sepet değiştirmede önceki yanıtta aldığın kimlikleri geri gönderiyorsun. Kural konmadan önce yazılmış zayıf bir kimlik dokümanda duruyorsa onu reddetmek ilgisiz satırlar dahil tüm isteğini düşürür ve dokümanı kalıcı kilitlerdi.Planlanan karar akışı (⏳ 2. ve 3. adıma bugün hiç ulaşılmıyor — şema ilk kapıda eliyor):
packets/create ve tables/create yeni satış açar — karşılaştırılacak mevcut doküman yoktur, her zayıf kimlik yeni beyandır ve 400 alır.<doküman kimliği>-<4 hex> kuruluyor ve kısa masa adlarında (b1, a1) toplam 7 karaktere düşüyordu: b1-1829. Üretim artık prefix'i telafi ediyor (b1-1d049). Senin geri gönderdiğin platform kimlikleri kuraldan geçer.(uuid, lineId) çiftini anahtar yapmaktır — uuid artık her olayda geliyor ve satış bazında kesin ayrık, çift bu hata sınıfını kuralın da ötesinde kapatır.Satırı dış sistemdeki karşılığına bağlayan opak alan (TSE imza referansı, kiosk oturumu, dış satır numarası). Bugüne kadar bu bilgi için taşıyıcı alan yoktu ve entegrasyonlar note alanını kirletiyordu. Platform yorumlamaz — ne fiyat/vergi hesabına, ne raporlamaya, ne de bir karara girer.
{ "tseRef": "TSE-9911" } düz map olarak anlatılmıştı; nihai şekil { key, value, by } dizisidir ve geriye uyum yoktur — map gönderen istek 400 metadata must be an array of {key, value} alır.// İSTEK — { key, value } dizisi (by GÖNDERİLMEZ)
{
"cart": [{
"product": "POS-11", "quantity": 1,
"lineId": "kiosk-a1",
"metadata": [ { "key": "tseRef", "value": "TSE-9911" } ]
}],
"payments": [{
"id": "m-cash", "price": 47,
"lineId": "kiosk-pay-1",
"metadata": [ { "key": "tseTx", "value": "77" } ]
}]
}// YANIT — platform her öğeye yazarı (by) damgalar
{
"orders": [
{ "id": "kiosk-a1", "lineId": "kiosk-a1", "productId": "POS-11",
"metadata": [ { "key": "tseRef", "value": "TSE-9911", "by": "hellokiosk" },
{ "key": "loyalty", "value": "L-2", "by": "sadakat" } ] }
],
"payments": [
{ "lineId": "kiosk-pay-1", "methodId": "m-cash", "amount": 47,
"metadata": [ { "key": "tseTx", "value": "77", "by": "fiskaly" } ] }
]
}by damgasını platform basar: istekte gönderirsen yok sayılır. Bu damga sayesinde iki eklenti aynı anahtarı çakışmadan kullanabilir ve kimsenin verisi bir başkası tarafından ezilemez. Kendi öğelerini by ile ayıkla — aynı satırda başkalarının öğeleri de bulunur.
| Kural | Davranış |
|---|---|
| Opsiyonel | Verilmezse alan hiç yazılmaz; okuma ucunda null döner |
| Opak | Platform yorumlamaz — hesaba, raporlamaya ya da bir karara girmez |
| Değer tipi | string, sonlu number veya boolean. İç içe obje / dizi / null → 400 |
| Sahiplik | by platformca damgalanır; çağıranın gönderdiği değer yok sayılır |
| Yazma yetkisi | Çağıran yalnız kendi öğelerini değiştirir/siler; başka eklentinin öğesine dokunamaz |
| Tam değiştirme | Uçlar full-replace olsa bile, aynı lineId yeniden beyan edildiği sürece diğer yazarların öğeleri korunur (altın kural) |
| Aynı anahtar | Aynı yazar bir anahtarı iki kez yazamaz (400); farklı yazarlar aynı anahtarı kullanabilir — by ayırır |
| Anahtar biçimi | Alfanümerik başlar, A-Za-z0-9_-, en çok 64 karakter |
| Round-trip | Yazıldığı gibi geri döner (packets/get, tables/get, webhook) |
// value: string | sonlu number | boolean
// key: alfanümerik başlar, A-Za-z0-9_- , ≤64
yazar başına ≤ 10 öğe / satır, value ≤ 256 karakter
istek başına ≤ 20 KB (cart ve payments AYRI bütçe)
belge geneli ≤ 100 KB (birleşme SONRASI tüm belge:
orders + payments + iptaller; seninkiler
+ korunan yabancı öğeler)
// reddedilir → 400
{ "tseRef": "TSE-9911" } // düz map (geriye uyum YOK)
[ { "key": "a", "value": { "b": 1 } } ] // iç içe obje
[ { "key": "a", "value": [1, 2] } ] // dizi
[ { "key": "a", "value": null } ] // nullBelge geneli bütçe, birçok eklentinin aynı adisyona yazdığı durumda Firestore belge sınırının zorlanmasını engeller. Aşım 400 döner ve mesaj aşımın kimden geldiğini söyler — kendi payload'ını küçültmenin çözüp çözmeyeceğini buradan anlarsın:
{
"success": false,
"status": 400,
"message": "Total metadata size after merge (108006) exceeds 102400 bytes
(yours: 18060, other plugins: 90300)"
}orders:read yeterlidir, PII rızası gerekmez. metadata tenant içi korelasyon verisidir — kiosk yazar, fiskal sağlayıcı okur. Bu yüzden görünürlük koşulu her kanalda aynıdır (okuma uçları, webhook fan-out'u, hook çağrısı): orders:read yeterlidir ve alan push gövdelerinden silinmez. Aynı ilke Google Drive'ın dosya properties alanında da geçerlidir. Buna karşılık note, paymentNote ve iptal reason bu kapsamda değildir: onlar gerçek kullanıcı girdisi taşır ve rıza kapısına tabi olmaya devam eder.metadata alanına ad, telefon, e-posta, adres veya kart bilgisi yazılamaz. Platform bu alanda desen taraması (e-posta/telefon regex'i) yapmaz: yanlış pozitif meşru bir mali kaydı reddedip satışı durdururdu. Kural sözleşme düzeyindedir, ihlal eklentinin sorumluluğundadır. Müşteri verisine erişim customers:read + rıza üzerinden yapılır.kuver.title) artık her akışta doludur ve şu sırayla çözülür: tenant ayarı (kuverText) → satışta hâlihazırda duran kuver satırının başlığı → "kuver". Önce bazı uçlar tenant metnini damgalıyor, alan istekte yoksa title undefined olup dokümandan düşüyordu — aynı tenant'ın bir fişinde işletmenin verdiği ad, diğerinde ham kimlik görünüyordu (DSFinV-K ARTIKELTEXT tutarsızlığı). ⚠️ Kuver satırı yalnız masa satışında oluşur; paket kanalında kuver satırı yoktur. (Sandbox'ta yayında, production'a çıkmadı.)metadata üzerinden sürdür (o satırla birlikte taşınır).lineChanges soy alanlarıyla (splitFrom / movedFrom) açıkça bildirilir — "sil + ekle" gibi görünen bu durumda storno yazmaman için. Hedefte aynı kimlik zaten varsa satır yeni kimlik alır ve movedFrom.lineId eski kimliği taşır. Ödeme→satır bağı da birlikte taşınır. Üretilen olaylar: tam taşımada hedef table.updated + kaynak table.deleted (deleteReason: moved_to_table | merged); kısmi taşımada iki table.updated.payOrders) satıra yeni lineId veriliyordu; mali tüketici bunu "eski satır silindi + yeni satır doğdu" görüp imzaladığı kaydı haksız yere storno ediyordu. Kimlik artık ömür boyu sabittir; ödeme↔satır ilişkisi ayrı bir tahsis kaydıyla kurulur (Square line_items[].uid, Toast selections[].guid, Stripe invoice_line_item.id deseni). ⚠️ Kısmi tahsilatta satır hâlâ bölünüyor ve parçalar yeni kimlik alıyor (bilinçli olarak ertelendi) — o senaryoda soyu lineChanges (splitFrom) üzerinden izle.lineId belongs to a cancelled line): aynı adisyonda aktif ve void satır aynı kimliği taşıyamaz, aksi halde "fişlendi mi, storno mu?" belirsizleşir.created zamanı (BQ/mali çıpa) her zaman taşınır; mutfak/depo alanları (ready, storages) yalnız ürün aynıysa taşınır — aynı lineId altında ürün değiştirmek bir değiştirme sayılır.lineId içerik değişmezliği garanti etmez: orders:write yetkili bir çağıran mevcut bir kimliği farklı ürün/fiyatla yeniden beyan edebilir (full-replace yetkisinin doğal sonucu). İmza doğrulaması mali sistemin işidir.kiosk-<sessionId>-<lineNo>) ve kendi tarafında sakla — tam-sepet değiştirmede aynı kimliği geri gönderirsen fiş/TSE zinciri kopmaz.null bekle: bu sürümden önce yazılmış satırlarda lineId/metadata null döner — payments[].id'ye fallback yapma (o alan yöntem id'si de olabilir → iki farklı satırı aynı kimlikle gösterirsin).metadata yazar başına 10 öğe / 256 karakter, istek başına 20 KB ya da belge geneli 100 KB sınırını aşarsa istek tümüyle 400 alır — büyük veriyi kendi tarafında tut, buraya yalnız anahtar yaz. Belge bütçesi paylaşılır: mesajdaki other plugins kırılımına bak, aşım senden gelmiyorsa payload'ını küçültmek çözmez.by ile ayıkla — okuma yanıtındaki dizi aynı satıra yazan tüm eklentilerin öğelerini taşır. İlk eşleşen anahtarı almak başka bir eklentinin verisini okumana yol açar.metadata'ya koyma — sözleşme yasağıdır ve platform taramaz, yani ihlal sessizce geçer; müşteri verisi için customers/get kullan.docNo) tüketmez. Sepet uçlarında hata mesajı ihlalin hangi ürün satırında, ödeme uçlarında hangi indekste olduğunu söyler.