Hangi tür?
Kasiyere göster: hiçbir kurulum gerekmez. Müşterinin telefonu sepeti tek tek barkod olarak gösterir; kasiyer kasanın kendi okuyucusuyla okutur. Her kasa ilk gün bununla başlayabilir ve her açık kasa gerektiğinde buna döner.
Kasa API'si: kasanızın ya da POS firmanızın bulutunun internette bir https adresi vardır. Müşteri “Sepeti kasaya aktar”a dokununca Shoppern'in sunucusu bu adrese sepeti, kasanın kendi biçiminde gönderir.
Örnek sepet
Shoppern kasanızın biçimini, herkes için aynı olan bu üç satırlık örnek sepetin sizin kasanızdaki yazılışından öğrenir. Barkodlar GS1'in tanıtım için ayırdığı 952 önekindendir; gerçek bir ürüne ait değildir.
| Adet | Barkod |
|---|---|
| 7 | 9521111111115 |
| 4 | 9522222222226 |
| 13 | 9523333333337 |
Adetler her basamakta farklıdır; satır sayısı (3), adetlerin toplamı (24) ve tek tek yazılmış kayıt sayısı (24) böylece birbirine karışmaz.
Örnek nasıl verilir
Örnek, kasanızın bu sepeti nasıl almak istediğidir. Shoppern onu adresinizden alır ya da panelde yapıştırırsınız. Üç türü vardır:
- Düz metin (text/plain): her ürün bir kayıt; barkod ve adet aynı düzende, aralarında aynı ayraç.
- JSON (application/json): içinde shoppern_till anahtarı olmayan her JSON; kayıtlar tek bir dizinin öğeleridir.
- Zarf: { "shoppern_till": 1, "send": "all" | "each", "content_type": …, "example": … }. each için example, çağrı başına bir gövdeden oluşan listedir.
Adet yerine barkodu adet kadar tekrar yazan bir kasa da olur (7 kez A, 4 kez B, 13 kez C): Shoppern bunu da öğrenir.
Barkodlar 14 haneye (başına 0) ve adetler sabit genişliğe (07) doldurulabilir; satır sayısı ve toplam adet kayıtların çevresinde durabilir. Shoppern bunları her sepet için yeniden yazar.
Örnekler ve Shoppern'in öğrendiği
7,9521111111115
4,9522222222226
13,9523333333337
Düz metin, sepetin tamamı tek çağrıda; adet önce, sonra barkod, aralarında virgül; her ürün ayrı satırda. 3 × A ve 1 × B şöyle gönderilir:
3,9521111111115
1,9522222222226
{"lines":3,"total":24,"items":[{"barcode":"9521111111115","qty":7},{"barcode":"9522222222226","qty":4},{"barcode":"9523333333337","qty":13}]}JSON, tek çağrıda; her üründe önce barkod, sonra adet; satır sayısı (3) ve toplam adet (24) her sepet için yeniden yazılır:
{"lines":2,"total":4,"items":[{"barcode":"9521111111115","qty":3},{"barcode":"9522222222226","qty":1}]}{"shoppern_till":1,"send":"each","content_type":"text/plain","example":["09521111111115;07","09522222222226;04","09523333333337;13"]}Düz metin, her ürün ayrı çağrıda; barkod önce (14 haneli), sonra adet (2 haneli), aralarında noktalı virgül. İki çağrı yapılır:
09521111111115;03
--- ayrı çağrı ---
09522222222226;01Shoppern ne gönderir
Müşteri “Sepeti kasaya aktar”a dokununca Shoppern adresinize bir POST yapar: all için sepetin tamamıyla bir çağrı, each için kayıt başına, sırayla birer çağrı. Her çağrı şu başlıkları taşır:
| Başlık | Anlamı |
|---|---|
| Content-Type | Öğrenilen içerik türü (text/plain ya da application/json). |
| Kasanın kendi başlıkları | Panelde girdiğiniz en fazla 5 başlık (API anahtarı gibi). |
| X-Shoppern-Checkout | Bu aktarımın kimliği (chk_…). |
| X-Shoppern-Timestamp | Çağrının zamanı, Unix saniyesi. |
| Idempotency-Key | <kasa>-<sepetin özeti>[-<n>]: aynı sepet için hep aynıdır; each'te n kaydın sırasıdır. |
| X-Shoppern-Signature | sha256=<hex>: aşağıdaki HMAC-SHA256 imzası. |
İmzayı ve zamanı doğrulama
İmza, panelde bir kez gösterilen 64 karakterlik imza anahtarıyla atılır. Anahtar, metnin kendisi olarak (64 ASCII baytı) kullanılır; onaltılık çözülmez.
imza = hex(HMAC-SHA256(anahtar, zaman + "." + Idempotency-Key + "." + gövde))
- X-Shoppern-Timestamp ile kendi saatiniz arasındaki fark 5 dakikadan fazlaysa çağrıyı reddedin.
- İmzayı aynı formülle kendiniz hesaplayın ve X-Shoppern-Signature ile sabit zamanlı karşılaştırın; tutmazsa reddedin.
- Idempotency-Key'leri saklayın: daha önce aldığınız bir anahtar yeniden gelirse sepeti ikinci kez okutmayın, ilk yanıtınızı yineleyin. Shoppern “Tekrar gönder”de aynı anahtarları kullanır.
- Yeni bir imza anahtarı panelde oluşturulur; eskisi o andan sonra imza atmaz.
const crypto = require("node:crypto");
function dogrula(istek, govde, anahtar) {
const zaman = istek.headers["x-shoppern-timestamp"];
const key = istek.headers["idempotency-key"];
const gelen = istek.headers["x-shoppern-signature"] ?? "";
if (Math.abs(Date.now() / 1000 - Number(zaman)) > 300) return false;
const beklenen =
"sha256=" +
crypto.createHmac("sha256", Buffer.from(anahtar, "ascii"))
.update(zaman + "." + key + "." + govde)
.digest("hex");
const a = Buffer.from(gelen);
const b = Buffer.from(beklenen);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Yanıtlar ne anlama gelir
Yanıtın yalnızca durumu ve (JSON ise, en fazla 4 KiB) üç alanı okunur; geri kalanı ve müşteriye hiçbir şey gösterilmez.
| Yanıt | Anlamı |
|---|---|
| 2xx | Alındı. |
| {"ok": false} | 2xx olsa da alınmadı. |
| {"accepted": n} | n satır alındı; geri kalanı alınmadı. |
| {"unknown": ["barkod", …]} | Bu barkodları tanımadınız; müşteriye “Kasada tanınmadı” denir. |
| 409 ya da 429 | Kasa meşgul; müşteriye biraz sonra denemesi söylenir. Kasanın hatası sayılmaz. |
| 404 ya da 422 (each, tek kayıt) | O satır reddedildi; aktarım kalanlarla sürer. |
| 400 ya da 415 | Biçim yanlış: kasa bir sonraki kullanımdan önce yeniden öğretilmelidir. |
| Zaman aşımı, kopan bağlantı | Bilinmiyor: kasa sepeti almış olabilir. Müşteri kasiyere sorar. |
| Diğer her şey | Başarısız; each'te kaç kaydın alındığı ve hangi satırda durduğu tutulur. |
Adres doğrulama ve örnek
Adresi doğrula: Shoppern adresinize bir GET yapar ve X-Shoppern-Challenge başlığında bir değer gönderir. Yanıtınız aynı başlığı aynı değerle geri göndermelidir. Adres değişince doğrulama yenilenir; doğrulanmamış bir adrese sepet gönderilmez.
Örneği adresten al: Shoppern adresinize X-Shoppern-Till: example ve Accept: application/json, text/plain başlıklarıyla bir GET yapar. Yanıtınız örnek sepetin kendi yazılışınız olmalıdır (en fazla 64 KiB). Örneği panelde yapıştırmak da olur.
Deneme gönder: örnek sepet gerçekten gönderilir ve X-Shoppern-Test: 1 ile işaretlenir. Bu işareti gören kasa okutmamalıdır.
Shoppern'in asla göndermedikleri
Kasaya yalnızca barkodlar ve adetler gider. Şunlar asla gönderilmez:
- Ürün adı ya da açıklaması
- Fiyat, tutar ya da vergi — parayı kasa hesaplar
- Müşterinin adı, telefonu ya da herhangi bir bilgisi
- Müşterinin geçmiş alışverişleri
Sınırlar
- Adres https olmalı, 443 numaralı kapıda, herkese açık bir DNS adıyla (IP adresi değil); en fazla 400 bayt.
- Bağlantı 3 saniyede kurulmalı, bir çağrı 6 saniyede bitmeli.
- Bir yanıtın en fazla 4 KiB'ı okunur; örnek en fazla 64 KiB olabilir.
- Bir sepet en fazla 200 satırdır; adetler 1 ile 99 arasındadır.
- Bir aktarım en fazla 60 çağrı (each) ve 2000 kayıttır (tekrar yazımda); daha büyük sepet için müşteri “Kasiyere göster”i kullanır.
- Kasanın günlük sepet sınırı paneldedir (en fazla 5000; doğrulanmamış hesapta 100).
- Yönlendirmeler izlenmez.
Çağrıların geldiği adres
Shoppern'in çağrıları aşağıdaki adreslerden gelir. POS bulutunuz bir izin listesi tutuyorsa bunları ekleyin.
179.198.202.51
Kasanızı panelde Kasalar sayfasından ekleyin.
Örneğinizi deneyin
Kasanızın örnek sepeti nasıl yazdığını yapıştırın; Shoppern'in ne öğreneceğini görün. Hiçbir şey kaydedilmez.