İçeriğe geç

Entegrasyon

Menüyü okumak

Kategoriler, porsiyonlar, ekstralar ve seçim grupları, kampanyalar, stok ve menünün bir kopyasını güncel tutmak.

Menü, sitenizin en sık okuyacağı şeydir. Bu rehber menünün yapısını, sipariş için gereken kimliklerin nereden geldiğini, kampanyaları ve stok durumunu ve menünün bir kopyasını sunucunuzda nasıl güncel tutacağınızı anlatıyor.

GET /venues/{venueId}/menu mekanın kategorilerini ve içlerindeki ürünleri verir: her ürünün porsiyonları ve fiyatları, ekstraları, seçim grupları, çıkarılabilir malzemeleri, alerjenleri ve stok durumu.

curl "https://api.cibusy.com/public/v1/venues/3fa85f64-5717-4562-b3fc-2c963f66afa6/menu?lang=tr" \
  -H "X-Api-Key: $CIBUSY_API_KEY"

Menüde yalnız mekanın misafirlerine gösterdikleri yer alır. Gizlenmiş bir ürün ya da kategori hiçbir zaman listelenmez, bu yüzden sipariş de edilemez. Menü, mekanın QR menüsünün nasıl ayarlandığından etkilenmez. Fiyatlar TL cinsinden ve KDV dahildir.

Text
data
└── categories[]                   kategoriler, mekanın gösterdiği sırayla
    └── products[]                 ürünler                     → productId
        ├── portions[]             porsiyonlar ve fiyatları    → portionId
        ├── extras[]               ekstralar                   → extraIds
        ├── optionGroups[]         ekstralar üzerindeki seçim kuralları
        └── removableIngredients[] çıkarılabilir malzemeler    → removedIngredientIds

Bir sipariş satırı bir ürünü (productId) bir porsiyonunda (portionId) adlandırır; isterse ekstralar ekler (extraIds) ve malzeme çıkarır (removedIngredientIds). Bu kimliklerin hepsi menüden gelir. Kategoriler ve ürünler zaten mekanın gösterdiği sırayla gelir; yeniden sıralamanız gerekmez.

Dil#

lang, mekanın dillerinden birinin iki harfli kodudur. Mekanın dilleri, mekanın bilgilerindeki languages listesindedir.

  • Mekanın sunmadığı bir dil istenirse ya da lang hiç verilmezse menü mekanın varsayılan dilinde gelir.
  • Yanıttaki language, metinlerin hangi dilde olduğunu söyler. Mekan hiç dil ayarlamadıysa null olur ve metinler mekanın yazdığı gibidir.
  • lang yalnız menünün dilini seçer. Hata mesajlarının dilini Accept-Language başlığı seçer.

Porsiyonlar ve fiyatlar#

Ürünün fiyatı porsiyonundadır. Her porsiyonun bir price değeri vardır; isDefault, mekanın önceden seçtiği porsiyonu gösterir. Tek servisi olan ürünlerde genellikle "Standart" adlı bir porsiyon bulunur; o zaman ürünün adını tek başına gösterin.

weight ve calories porsiyonun üzerinde yazan gramaj ve enerjidir. Bunlar porsiyonun adının yanında gösterilecek bilgilerdir; fiyat bunlarla hesaplanmaz.

Kampanyalar#

Süren bir indirimin kapsadığı porsiyon, gösterilecek fiyatla birlikte bir campaign taşır:

JSON
{
  "id": "b9f2a7d4-3e05-4c81-86b7-2d8e0f1a4b35",
  "name": "Yarım porsiyon",
  "price": 190,
  "orderable": true,
  "campaign": {
    "campaignId": "0c2e4a6b-8d1f-4a3c-9e5b-7d9f1b3d5f70",
    "name": "Öğle menüsü",
    "badgeText": "%15",
    "discountedPrice": 161.5,
    "endsAt": "2026-10-01T12:00:00.000Z"
  }
}

price değerinin yanında discountedPrice gösterin; badgeText rozet için kısa bir etikettir, endsAt de bir geri sayım için kampanyanın bittiği an. Kampanya her çağrıda yeniden hesaplanır, bu yüzden bir happy hour tam zamanında başlar ve biter.

Burada yalnız porsiyonun kendisindeki düz indirimler görünür. Menü kampanyaları ve "iki al bir öde" gibi indirimler sepet fiyatlanırken uygulanır ve sepeti fiyatladığınızda discount alanında görünür.

Tartıyla satılan ürünler#

orderable: false olan porsiyon ölçüyle satılır. pricingUnit fiyatın hangi birim için olduğunu söyler, örneğin Kilogram, ve misafirin aldığı miktar mekanda tartılır. Böyle bir porsiyonu menünüzde gösterebilirsiniz ama API üzerinden sipariş edemezsiniz.

Ekstralar ve seçim grupları#

extras ürüne eklenebilecekleri fiyatlarıyla listeler. Bir ekstranın price değeri, birlikte sipariş edildiği porsiyonun fiyatına eklenir; ücretsiz bir ekstrada sıfırdır.

optionGroupId dolu olan ekstralar bir seçim grubunun seçenekleridir. Grup, o seçenekler üzerinde bir kural koyar:

AlanKural
selectionType: "Single"Gruptan en fazla bir seçenek seçilebilir.
selectionType: "Multiple"Gruptan istenen sayıda seçenek seçilebilir.
isRequired: trueGruptan bir seçim yapılmadan ürün sipariş edilemez.

Örnek menüdeki ızgara köftede "Pişirme" zorunlu ve tek seçimli bir gruptur: "Az pişmiş" ve "İyi pişmiş" seçeneklerinden tam olarak biri seçilmelidir. "Ekstra peynir" hiçbir gruba ait değildir ve serbestçe eklenir.

Seçilen ekstraların kimlikleri siparişte extraIds alanında gider ve satırın her adedi için geçerlidir. Ürünün kendi ekstrası olmayan, iki kez yazılan ya da bir grubun kuralını bozan bir seçim 400 PUBLIC_API_PRODUCT_OPTION_INVALID ile reddedilir.

Çıkarılabilir malzemeler#

removableIngredients, misafirin üründen çıkarılmasını isteyebileceği malzemelerdir; soğan gibi. Siparişte removedIngredientIds alanında gider ve satırın her adedi için geçerlidir.

Stok ve ürün bilgileri#

  • stockStatus ürünün stokta (InStock), azalıyor (LowStock) ya da tükenmiş (OutOfStock) olduğunu söyler. Mekan ürünün stokunu takip etmiyorsa null olur; o zaman bir rozet göstermeyin. Tükenen ürün menüde kalır ama onun için verilen sipariş 409 PUBLIC_API_PRODUCT_UNAVAILABLE ile reddedilir.
  • allergens mekanın ürün için bildirdiği alerjenlerdir (AB yönetmeliğindeki 14 alerjen). Boş bir liste, ürünün alerjen içermediği anlamına gelmez; mekanın bir alerjen bildirmediği anlamına gelir.
  • containsAlcohol ve containsPorkDerivatives ürünün alkol ya da domuz türevi içerip içermediğini söyler. true olduğunda menünüzde bunu bir etiketle gösterin.
  • acceptsMealCard, mekanın bu ürün için yemek kartı kabul edip etmediğidir.

Menüyü sitenizin her ziyaretçisi için yeniden istemeyin. Bir kopyasını sunucunuzda tutun ve kullanmadan önce hala güncel olup olmadığını sorun:

  1. Menüyü okuduğunuzda yanıtın ETag başlığını kopyayla birlikte saklayın.
  2. Sonraki istekte bu değeri If-None-Match başlığında gönderin.
  3. Menü değişmediyse yanıt gövdesiz bir 304 Not Modified olur ve kopyanızı kullanmaya devam edersiniz. Değiştiyse yeni menü yeni bir ETag ile gelir.
JavaScript
const menus = new Map(); // "venueId:lang" → { etag, menu }

async function getMenu(venueId, lang) {
  const key = `${venueId}:${lang}`;
  const cached = menus.get(key);

  const headers = { 'X-Api-Key': process.env.CIBUSY_API_KEY };
  if (cached) headers['If-None-Match'] = cached.etag;

  const response = await fetch(
    `https://api.cibusy.com/public/v1/venues/${venueId}/menu?lang=${lang}`,
    { headers }
  );
  if (response.status === 304) return cached.menu;

  const body = await response.json();
  if (!body.success) throw new Error(`${body.errorCode}: ${body.developerMessage}`);

  menus.set(key, { etag: response.headers.get('ETag'), menu: body.data });
  return body.data;
}
  • Cibusy bir menüyü en fazla beş dakika önbellekte tutar ve mekan menüyü düzenlediğinde hemen yeniler.
  • ETag zarfın değil, data alanının karşılığıdır: zarfın timestamp değeri her çağrıda değişse de menü aynıysa ETag aynı kalır.
  • Yanıt Cache-Control: private, no-cache der: kopyayı saklayın, ama kullanmadan önce güncel olup olmadığını sorun.

Kopyanızı her ziyaretçide değil, belirli aralıklarla doğrulayın: örneğin en çok dakikada bir. Böylece hem hız sınırının çok altında kalırsınız hem de menüdeki bir değişiklik sitenize bir dakika içinde yansır.