Katalog Yazma — Ortak Kurallar

Ürün, kategori, ödeme yöntemi ve malzeme yazma uçlarının (create/update/delete) ORTAK kuralları: scope'lar, sahiplik modeli, idempotency, hata mesajları ve webhook echo. Her ucun gövdesi/alanları kendi kaynak sayfasındadır.

← API Uçları · Uçlar: products/* · categories/* · payment-methods/* · ingredients/*.

Genel & scope'lar

Method / yolPOST /plugin-api/{entity}/{create|update|delete}
Entity'lerproducts · categories · payment-methods · ingredients
Authinstall API key — Authorization: Bearer serverId.pluginId.secret
Rate limitOrtak write kovası (varsayılan 20/dk) — Limitler
UçlarScopeNot
products/* + categories/*products:writeKategoriler ürün/menü domain'inin parçası — ayrı scope yok
payment-methods/*payment_methods:write
ingredients/*ingredients:write

Sahiplik modeli (ZORUNLU kural)

  • create ile oluşturduğunuz her kayıt eklentinize damgalanır (sahiplik).
  • update ve delete yalnız KENDİ oluşturduğunuz kayıtlarda çalışır — işletmenin veya başka eklentinin kaydını düzenleyemez/silemezsiniz → plugin.catalog.notOwned. (Slack chat.delete deseni.)
  • İşletme personeli panelden sizin kayıtlarınızı da düzenleyip silebilir (tam yetki). Personel düzenlemesi sahiplik damgasını korur — kayıt "sizin" kalır.
  • Hangi kayıtların size ait olduğunu create yanıtındaki id ile kendi tarafınızda takip edin; okuma uçları sahiplik bilgisi döndürmez.

Idempotency

Tüm create uçları: idempotencyKey (≤128 char, önerilir) → retry'da duplicate yazmaz, ilk başarılı yanıtı aynen döner (24sa pencere; eklenti+tenant+entity başına). Eşzamanlı 2. istek işlenirken → plugin.catalog.duplicateInProgress (kısa bekle, aynı key ile tekrar dene). update/delete doğal idempotenttir (silinmiş kayda tekrar delete → plugin.catalog.notFound).

Hata mesajları

Hatalar HTTP 200 + { success:false, message } (rate limit 429 hariç).

messageAnlam
joi doğrulama mesajıEksik/yanlış tip alan veya tanımsız alan (kütle-atama engeli)
plugin.scope.deniedGerekli yazma scope'u onaylı değil
plugin.catalog.notFoundid ile kayıt bulunamadı
plugin.catalog.notOwnedKayıt sizin eklentinizce oluşturulmamış (update/delete reddi)
plugin.catalog.categoryNotFoundÜründe verilen category id'si yok
plugin.catalog.categoryNotEmptySilinmek istenen kategoriye bağlı ürünler var
plugin.catalog.duplicateInProgressAynı idempotencyKey ile eşzamanlı 2. istek
plugin.rateLimitedwrite kovası aşıldı (HTTP 429)

Webhook etkileşimi (echo dahil)

Her başarılı yazma ilgili kanonik event'i tetikler (product.* · category.* · payment_method.* · ingredient.*).

Event abone tüm eklentilere gider — çağrıyı yapan eklenti dahil (echo; Shopify/Stripe davranışı). Kendi yazmanızı ayırt etmek için create yanıtındaki id'yi saklayıp event data.id ile eşleyin. Event data'sı bu uçların yanıt data'sıyla aynı şekildedir.

Örnek (curl)

# Kategori oluştur → dönen id ile ürün oluştur
curl -X POST https://plugins.restomenum.app/plugin-api/categories/create \
  -H "Authorization: Bearer <serverId>.<pluginId>.<secret>" -H "Content-Type: application/json" \
  -d '{ "title": "Tatlılar", "idempotencyKey": "cat-1" }'

curl -X POST https://plugins.restomenum.app/plugin-api/products/create \
  -H "Authorization: Bearer <serverId>.<pluginId>.<secret>" -H "Content-Type: application/json" \
  -d '{ "title": "Cheesecake", "price": 120, "category": "<kategori-id>", "idempotencyKey": "prod-1" }'

# Sahip olmadığınız kaydı silme → plugin.catalog.notOwned
curl -X POST https://plugins.restomenum.app/plugin-api/products/delete \
  -H "Authorization: Bearer <serverId>.<pluginId>.<secret>" -H "Content-Type: application/json" \
  -d '{ "id": "panelden-olusan-id" }'