POST /plugin-api/packets/create ✓ CanlıEklentinin Restomenum'da yeni paket/delivery siparişi oluşturduğu yazma ucudur. Okuma uçlarından farklı: POST, JSON gövde alır ve orders:write scope'u ister. Sepet ürün id'leriyle gönderilir; fiyatlar Restomenum ürün kaydından alınır (gönderdiğiniz fiyat yok sayılır). idempotencyKey ile retry'da çift sipariş oluşmaz.
← API Uçları · ortak kurallar (base, auth, hata zarfı) orada.
| Method / yol | POST /plugin-api/packets/create |
| Auth | install API key — Authorization: Bearer serverId.pluginId.secret |
| Scope | orders:write |
| Rate limit | Ayrı write kovası (varsayılan 20/dk; okuma kovasından sıkı) — Limitler |
| Content-Type | application/json |
POST {RESTOMENUM_BASE}/plugin-api/packets/create
Authorization: Bearer <apiKey> // install API key: serverId.pluginId.secret
Content-Type: application/jsonhttps://sandbox.plugins.restomenum.app, Production https://plugins.restomenum.app (API Uçları).Authorization: Bearer <apiKey> — token exchange'teki install API key.{
"customer": { // zorunlu
"id": "cust-123", // zorunlu
"name": "Ahmet Bayrak", // zorunlu
"address": "Örnek Mah. ...", // zorunlu
"region": "Kadıköy", // ops
"addressDescription": "3. kat", // ops
"phone": "5xx...", // ops
"call": "5xx..." // ops
},
"cart": [ // zorunlu, 1..200 kalem
{
"product": "3b5d-f6d0", // ürün id (products/list id'si) — zorunlu
"quantity": 2, // zorunlu (0..9999)
"options": ["çilek", "bal"], // ops — opsiyon ADLARI (string)
"discount": 0, // ops (>= 0)
"note": "az pişmiş" // ops
}
],
"paymentNote": "nakit", // zorunlu
"payments": [ // ops (<= 20). price >= 0; price > 0 olanlar saklanır
{ "id": "pm-1", "title": "Nakit", "price": 130, "isDiscount": false }
],
"note": "Kapıda zil çalma", // ops
"status": "Approved", // ops: 'none' | 'Approved' (default 'Approved')
"restaurantDelivery": true, // ops (default true)
"idempotencyKey": "order-9af2...", // ops AMA ÖNERİLİR (retry'da çift sipariş engeller)
"callbackUrl": "https://..." // ops (https, ≤500) — SAHİPLİK damgası + status hedefi; webhookUrl ile AYNI domain ŞART
}| Alan | Tip | Zorunlu | Açıklama |
|---|---|---|---|
| customer | object | evet | id, name, address zorunlu; region, addressDescription, phone, call opsiyonel. |
| cart[] | array | evet | 1..200 kalem. Her kalem: product (ürün id, zorunlu), quantity (0..9999, zorunlu), options (opsiyon adları — string dizisi), discount (≥0), note. |
| paymentNote | string | evet | Ödeme notu (ör. "nakit"). |
| payments[] | array | hayır | ≤20. { id, title, price, isDiscount? }. price ≥ 0; yalnız price > 0 saklanır. Normal satır: id tenant'ın gerçek yöntemi olmalı (payment-methods/list'ten al); title yok sayılır. isDiscount:true: doğrulamadan muaf (serbest id), title zorunlu. Aşağı bkz. |
| note | string | hayır | Sipariş notu (ör. "Kapıda zil çalma"). |
| status | string | hayır | 'none' | 'Approved' — varsayılan 'Approved'. |
| restaurantDelivery | boolean | hayır | Restoranın kendi kuryesiyle teslim — varsayılan true. |
| idempotencyKey | string | önerilir | Kendi benzersiz sipariş anahtarın. Aynı anahtarla retry → aynı paket, çift sipariş yazmaz (24sa pencere). |
| callbackUrl | string (https) | hayır | Sahiplik damgası + status-bildirim hedefi. Kurallar: https, ≤500 karakter, manifest webhookUrl'ünüzle aynı registered domain, private IP'ye çözünmemeli (ihlalde 400). Aşağı bkz. |
// başarı
{ "success": true, "data": { "packetId": "a1b2c3-uuid" } }
// hata
{ "success": false, "message": "<açıklama>" }data.packetId oluşan paketin id'sidir → tam detayı packets/get?packetId= ile çekebilirsin.
| message | Anlam |
|---|---|
| joi doğrulama mesajı | Geçersiz gövde (eksik/yanlış alan). |
| Product not found: <id> | cart'taki bir ürün mağazada yok (TÜM ürünler var olmalı). |
| unknown_payment_method | Normal ödeme satırının id'si tenant'ın tanımlı yöntemi değil (400). Önce payment-methods/list. |
| no_payment_methods_configured | Tenant'ta hiç ödeme yöntemi tanımlı değil (400; id yanlışlığından ayrı kod). |
| Paid amount is greater than total… | payments toplamı sipariş tutarını aşıyor. |
| Server not found | Geçersiz tenant. |
| Duplicate request already in progress | Aynı idempotencyKey ile eşzamanlı 2. istek. |
| plugin.scope.denied | orders:write onaylı değil. |
| callbackUrl must be under the same domain… | callbackUrl manifest webhookUrl'ünüzle aynı registered domain'de değil. |
| callbackUrl rejected: <sebep> | callbackUrl güvenlik kontrolünden geçemedi (private IP / DNS hatası vb.). |
product (id) + quantity + options (ad) + discount verirsiniz. (Güvenlik: client fiyat iddiası kabul edilmez.) payments[].price ödeme tutarıdır, ürün fiyatı değil.id'si tenant'ın gerçek bir yöntemi olmalı — keyfi id → unknown_payment_method. title yöntem kaydından türetilir (yok sayılır). İndirim satırları (isDiscount:true) muaftır ve title gerektirir.idempotencyKey gönderin. Ağ retry / tekrar tesliminde aynı paketi döndürür, çift sipariş yazmaz (24sa pencere).Product not found).options = opsiyon adları (string dizisi); fiyatlarını backend belirler.entegrasyon: "packet" ile yazılır; packet.created event'i abone eklentilere düşer.Bu uç paketi oluşturur. Sonradan status'ü sürmek (Approved → OnDelivery → Delivered) için bu ucu DEĞİL, packets:status scope'u + status callback'lerini kullanın: packet.created event'inde size imzalı callbackUrl'ler (pickup / delivered / cancel) verilir; teslim/iptal durumlarını onları çağırarak setlersiniz (Getir/Yemeksepeti deseni — platform kendi siparişinin teslim durumunu sürer).
callbackUrl = sahiplik damgası. Paketi sizin oluşturduğunuzu işaretler ve ileride statü bildirimlerinin hedefi olur. Sahiplik damgası packet.status.update gate'ini açar: restoran sizin oluşturduğunuz paketin statüsünü değiştirmeden önce size sorulur (allow/deny). (packet.close ise tenant-geneldir, sahiplik/callbackUrl gerektirmez.) Kurallar: https, ≤500 karakter, manifest webhookUrl'ünüzle aynı registered domain, private IP'ye çözünmemeli (ihlalde 400).packet.status_changed) —callbackUrl şimdilik saklanır + sahiplik/hook'u açar, ama statü değişiminde henüz çağrı yapılmaz. Status'ü siz setlemek istiyorsanız packets:status + statusCallback yolunu kullanın (yukarıda).curl -X POST https://plugins.restomenum.app/plugin-api/packets/create \
-H "Authorization: Bearer <serverId>.<pluginId>.<secret>" \
-H "Content-Type: application/json" \
-d '{
"customer": { "id": "c1", "name": "Test", "address": "Adres" },
"cart": [ { "product": "3b5d-f6d0", "quantity": 1 } ],
"paymentNote": "nakit",
"idempotencyKey": "order-9af2"
}'