Bir Tıkla YemekGeliştirici

Bir Tıkla Yemek Entegrasyon API

POS, muhasebe ve yazar kasa entegrasyonu

Siparişler POS’unuza anında düşsün, mutfak fişi otomatik basılsın, onay / hazırlık / teslim adımları iki yönlü senkron kalsın; yazar kasa (ÖKC) fişi, e-Arşiv ve e-Fatura için hazır KDV kırılımı alın, gün sonunda Z raporunuzu tek uçla mutabık edin. REST + JSON, imzalı webhook’lar ve gerçek veriye dokunmayan tam işlevli bir sandbox.

Sipariş akışı

Listele, onayla, reddet, hazırla, teslim et, gecikme bildir

Anlık webhook

HMAC imzalı, otomatik yeniden denemeli olaylar

Yazar kasa & e-belge

KDV kırılımlı fiş gövdesi, belge no bildirimi

Gün sonu

Ödeme tipi, KDV, komisyon, eksik fiş listesi

# 1) Bağlantıyı test edin
curl https://birtiklayemek.com/api/v1/me -H "Authorization: Bearer btk_test_XXXXXXXX"

# 2) Sandbox'ta test siparişi oluşturun (webhook'unuza order.created gelir)
curl -X POST https://birtiklayemek.com/api/v1/sandbox/orders \
  -H "Authorization: Bearer btk_test_XXXXXXXX" -H "Content-Type: application/json" -d '{}'

# 3) Onaylayın
curl -X POST https://birtiklayemek.com/api/v1/orders/{id}/accept \
  -H "Authorization: Bearer btk_test_XXXXXXXX" -H "Content-Type: application/json" \
  -d '{"deliveryMethod":"own"}'

Sandbox ve canlı ortam

İki ortam aynı adresi kullanır: https://birtiklayemek.com/api/v1. Ortamı anahtarın öneki belirler. Anahtarlar restoran panelinde Entegrasyonlar sayfasından oluşturulur; sağlayıcı firmalar restorandan sandbox anahtarı isteyerek geliştirmeye başlar.

SandboxCanlı
Anahtar önekibtk_test_…btk_live_…
SiparişlerTest siparişleri (POST /sandbox/orders veya paneldeki “Test siparişi”)Gerçek müşteri siparişleri
Kontör / komisyon / müşteri bildirimiHiçbiri — gerçek veriye dokunmazOnayda kontör düşer, müşteriye bildirim gider
Menü güncellemeDoğrulanır, kaydedilmez (persisted: false)Kaydedilir, müşteriye anında yansır
Platform olaylarıPOST /sandbox/orders/{id}/simulate ile taklit edilirMüşteri, kurye ve yönetici tarafından gerçekleşir
Webhook adresihttp / https, localhost dahilYalnızca https ve herkese açık adres
Durum makinesi, hata kodları, imzaCanlıyla birebir aynı—
# Paketçiniz kuryesinin siparişi alması, müşteri iptali vb.
curl -X POST https://birtiklayemek.com/api/v1/sandbox/orders/{id}/simulate \
  -H "Authorization: Bearer btk_test_…" -H "Content-Type: application/json" \
  -d '{"event":"courier_assigned"}'   # customer_cancelled | courier_assigned | courier_picked_up | delivered

Kimlik doğrulama ve yetkiler

Her istekte Authorization: Bearer <anahtar> (veya X-API-Key) gönderin. Anahtar bir restorana (şubeye) bağlıdır; zincirlerde her şube için ayrı anahtar oluşturulur. Tam anahtar yalnızca oluşturulurken bir kez gösterilir, sunucuda yalnızca özeti (SHA-256) saklanır. Anahtarı yalnızca sunucu tarafında tutun; tarayıcı veya mobil uygulama koduna gömmeyin.

Yetki (scope)Açıklama
orders:readSiparişleri okuma
orders:writeSipariş durumunu güncelleme (onay, ret, hazır, teslim, gecikme)
menu:readMenü ve fiyatları okuma
menu:writeStok / fiyat / KDV güncelleme
accounting:readGünlük satış ve KDV raporu
fiscal:writeMali belge (ÖKC fişi, e-Arşiv, e-Fatura) bildirme

İstek ve yanıt kuralları

  • JSON gövde, UTF-8. Başarılı yanıt { data: … }, liste uçlarında { data: [...], nextCursor }.
  • Tutarlar TL, KDV dahil, sayı olarak 2 ondalık (ör. 129.9). Para birimi alanı: TRY.
  • Tarihler ISO 8601 UTC (2026-10-16T12:30:00.000Z). Gün sonu raporu İstanbul gününe göredir.
  • Oran sınırı: anahtar başına dakikada 120 istek. Yanıtta X-RateLimit-Remaining, aşımda 429 + Retry-After.
  • Her yanıtta BTK-Request-Id bulunur; destek taleplerinde bu kimliği iletin.
  • Durum geçişleri idempotenttir: sipariş zaten hedef durumdaysa 200 döner, aynı isteği güvenle yeniden deneyin.
  • Sipariş uçlarında {id} yerine sipariş numarası (orderNumber) da kullanılabilir.
  • Bilinmeyen yeni alanlar eklenebilir; istemciniz tanımadığı alanları yok saymalıdır.

Sipariş akışı (durum makinesi)

RESTAURANT_PENDINGRESTAURANT_ACCEPTEDPREPARINGREADY_FOR_PICKUPON_THE_WAYDELIVEREDYan yollar: RESTAURANT_PENDING → RESTAURANT_REJECTED · READY_FOR_PICKUP → COURIER_ASSIGNED → PICKED_UP → ON_THE_WAY (Paketçiniz) · onaydan önce/sonra → CANCELLED (müşteri / yönetici)
DurumAnlamıKim değiştirirAPI ile sonraki adım
RESTAURANT_PENDINGYeni sipariş, onay bekliyorMüşteriaccept / reject
RESTAURANT_ACCEPTEDOnaylandı, kontör düştüRestoran / POSstatus: PREPARING
RESTAURANT_REJECTEDReddedildi (kontör düşmez)Restoran / POS— (son durum)
PREPARINGMutfakta hazırlanıyorRestoran / POSstatus: READY_FOR_PICKUP
READY_FOR_PICKUPHazır, kurye bekliyorRestoran / POSstatus: ON_THE_WAY (kendi kurye) · Paketçiniz kuryesi alır
COURIER_ASSIGNEDPaketçiniz kuryesi atandıPlatformkurye adımları platformdan
PICKED_UPKurye teslim aldıPlatform—
ON_THE_WAYYoldaRestoran / POS veya platformstatus: DELIVERED
DELIVEREDTeslim edildi (komisyon kesinleşir)Restoran / POS, kurye, müşteri onayı— (son durum)
CANCELLEDİptal (müşteri / yönetici)Platform— (son durum)

Ret nedenleri (reasonCode — zorunlu)

KodMüşteriye görünen
OUT_OF_STOCKÜrün tükendi
TOO_BUSYRestoran çok yoğun
CLOSINGKapanış saatine yakın
OUT_OF_ZONEAdres teslimat bölgesi dışında
CUSTOMER_UNREACHABLEMüşteriye ulaşılamadı / şüpheli sipariş
OTHERDiğer

Gecikme nedenleri (+10 / +20 / +30 dk)

KodEtiket
WEATHERHava muhalefeti
BUSYYoğunluk
TRAFFICTrafik
COURIERKurye gecikmesi
KITCHENHazırlık uzadı

Önemli: Reddedilen siparişte kontör düşmez; ret nedenleri ve müşteri bildirimleri risk analizine girer. Siparişi reddedip platform dışında teslim etmek sözleşmeye aykırıdır. Teslim edilen siparişi mutlaka DELIVERED olarak işaretleyin; işaretlenmeyen teslimatlar 3 saat sonra sistemce kapatılır.

Önerilen POS / adisyon akışı

  1. 1

    order.created webhook'u gelir

    Webhook'u doğrulayıp 200 dönün; ayrıca her 60 sn'de GET /orders?updatedSince=… ile yoklayın (webhook kaçarsa güvenlik ağı).

  2. 2

    Siparişi POS'a aktarın

    GET /orders/{id} ile ürün, seçenek, çıkarılan malzeme ve notları adisyona yazın. menuItemId ile POS ürününüzü eşleştirin (GET /menu).

  3. 3

    Onaylayın veya reddedin

    POST /orders/{id}/accept (deliveryMethod: own | paketciniz) ya da POST /orders/{id}/reject { reasonCode }. Hedef: 3 dakika içinde.

  4. 4

    Mutfak fişini basın

    Onaydan sonra; ileri tarihli siparişte (scheduledFor) hazırlığa teslim saatine göre başlayın.

  5. 5

    Hazırlık adımları

    POST /orders/{id}/status → PREPARING → READY_FOR_PICKUP. Gecikme olursa POST /orders/{id}/delay.

  6. 6

    Teslimat

    Kendi kuryeniz: ON_THE_WAY → DELIVERED. Paketçiniz: kurye adımları platformdan order.status_changed olarak gelir.

  7. 7

    Mali belge

    GET /orders/{id}/fiscal gövdesiyle ÖKC fişini / e-Arşivi kesin, POST /orders/{id}/fiscal ile belge numarasını bildirin.

  8. 8

    Gün sonu

    Z raporundan önce GET /accounting/daily ile ödeme tipi ve KDV toplamlarını karşılaştırın; fiscal.missing listesini sıfırlayın.

Webhook’lar

Panelde anahtar için bir adres tanımlayın; olaylar POST ile JSON olarak gönderilir. 10 sn içinde 2xx dönmezseniz 1 dk, 5 dk, 30 dk, 2 sa, 6 sa, 12 sa sonra yeniden denenir (toplam 7 deneme). Yönlendirmeler (3xx) izlenmez. Aynı olay birden fazla gelebilir: id (evt_…) ile tekilleştirin; sıra garanti değildir, siparişin updatedAt alanına göre en yenisini esas alın.

OlayNe zaman
order.createdYeni sipariş geldi (onay bekliyor)
order.status_changedSipariş durumu değişti
order.cancelledSipariş reddedildi / iptal edildi
order.delayedGecikme bildirildi
fiscal.recordedMali belge kaydedildi
webhook.testPanelden veya POST /webhooks/test ile gönderilen deneme olayı
BaşlıkAçıklama
BTK-Signaturet=<unix zaman>,v1=<HMAC-SHA256 hex> — v1 = HMAC(webhookSecret, `${t}.${ham gövde}`)
BTK-EventOlay adı
BTK-Event-IdOlay kimliği (tekilleştirme)
BTK-Delivery-IdTeslimat kimliği (paneldeki günlükle eşleşir)
BTK-AttemptDeneme sayısı (1, 2, …)
{
  "id": "evt_3f9a1c0b7d2e4a5f6b7c8d9e",
  "type": "order.created",
  "apiVersion": "2026-10-01",
  "environment": "live",
  "createdAt": "2026-10-16T12:30:01.120Z",
  "restaurantId": "rst_123",
  "data": {
    "order": "{ …sipariş nesnesi (GET /orders/{id} ile aynı) }"
  }
}

İmza doğrulama

import crypto from "node:crypto";
import express from "express";

const app = express();
const SECRET = process.env.BTK_WEBHOOK_SECRET; // whsec_…

// İmza HAM gövde üzerinden hesaplanır: JSON'u parse etmeden önce doğrulayın
app.post("/btk-webhook", express.raw({ type: "application/json" }), (req, res) => {
  const parts = Object.fromEntries(
    (req.get("BTK-Signature") ?? "").split(",").map((p) => p.split("=")),
  );
  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(`${parts.t}.${req.body}`)
    .digest("hex");
  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  const valid =
    fresh &&
    parts.v1?.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
  if (!valid) return res.status(400).send("imza geçersiz");

  const event = JSON.parse(req.body);
  // Aynı olay yeniden gelebilir: event.id ile tekilleştirin
  queue.push(event); // işi kuyruğa alın, hemen 200 dönün
  res.sendStatus(200);
});

Yazar kasa (ÖKC), e-Arşiv ve e-Fatura

  • • Menü fiyatları KDV dahildir. Her ürünün KDV oranı menüde tutulur (varsayılan %10; 0, 1, 10, 20 desteklenir) ve siparişte satır bazında gelir.
  • • İndirim, ürün tutarlarına orantılı dağıtılır; kuruş farkı son KDV grubuna yazılır, toplam birebir korunur.
  • • Teslimat ücreti %20 KDV ile ayrı satırdır.
  • • Platform hizmet bedeli restoran fişine yazılmaz; Bir Tıkla Yemek faturalar. Kapıda ödemede müşteriden tahsil edilecek tutar payment.collectFromCustomer alanındadır.
  • • Online ödenmiş siparişte collectFromCustomer 0’dır; fiş yine kesilir, ödeme tipi ONLINE olarak eşlenir.
Ödeme yöntemiKodÖKC ödeme tipi
Kapıda nakitCASH_ON_DELIVERYNAKIT
Kapıda kartCARD_ON_DELIVERYKREDI_KARTI
Online kartONLINE_CARDONLINE
CüzdanWALLETONLINE
MultinetMULTINETYEMEK_KARTI
SetcardSETCARDYEMEK_KARTI
SodexoSODEXOYEMEK_KARTI
MetropolMETROPOLYEMEK_KARTI
Ticket RestaurantTICKETYEMEK_KARTI

GET /orders/{id}/fiscal yanıtı

{
  "data": {
    "orderId": "cmv3k2q9x0001abcd",
    "orderNumber": "BTE-5Y0H1938",
    "currency": "TRY",
    "pricesIncludeVat": true,
    "lines": [
      {
        "menuItemId": "cmmenu0001",
        "name": "Tavuklu Pilav",
        "quantity": 2,
        "unitPrice": 125,
        "total": 250,
        "vatRate": 10
      },
      {
        "menuItemId": "cmmenu0002",
        "name": "Ayran",
        "quantity": 2,
        "unitPrice": 25,
        "total": 50,
        "vatRate": 10
      },
      {
        "menuItemId": "DELIVERY",
        "name": "Teslimat ücreti",
        "quantity": 1,
        "unitPrice": 20,
        "total": 20,
        "vatRate": 20
      }
    ],
    "discount": {
      "amount": 30,
      "allocation": "proportional_to_items"
    },
    "vatSummary": [
      {
        "rate": 10,
        "base": 245.45,
        "vat": 24.55,
        "gross": 270
      },
      {
        "rate": 20,
        "base": 16.67,
        "vat": 3.33,
        "gross": 20
      }
    ],
    "receiptTotal": 290,
    "vatTotal": 27.88,
    "payment": {
      "method": "CASH_ON_DELIVERY",
      "okcPaymentType": "NAKIT",
      "paidOnline": false,
      "collectFromCustomer": 300
    },
    "platformServiceFee": {
      "amount": 10,
      "note": "Platform hizmet bedeli restoran fişine yazılmaz; Bir Tıkla Yemek tarafından faturalanır."
    },
    "customer": {
      "name": "Ayşe Yılmaz",
      "phone": "05551112233"
    },
    "alreadyIssued": null
  }
}

Belge kesildikten sonra

curl -X POST https://birtiklayemek.com/api/v1/orders/{id}/fiscal \
  -H "Authorization: Bearer btk_live_…" -H "Content-Type: application/json" \
  -d '{"type":"OKC_RECEIPT","documentNumber":"0042","zReportNo":"1187","ekuNo":"3","issuedAt":"2026-10-16T13:05:00+03:00"}'

# e-Arşiv:  {"type":"E_ARSIV","documentNumber":"BTK2026000000123","issuedAt":"…","documentUrl":"https://…/pdf"}

Muhasebe ve gün sonu (Z raporu mutabakatı)

GET /accounting/daily?date=YYYY-AA-GG İstanbul gününün siparişlerini özetler. Ciroya yalnızca teslim edilen siparişler girer. Muhasebe programınıza satış (KDV matrah/tutar), tahsilat (ödeme tipine göre) ve platform gideri (komisyon + platform ücreti) kayıtlarını bu rapordan oluşturabilirsiniz; restaurantNet mutabakat tutarınızdır.

{
  "data": {
    "date": "2026-10-16",
    "currency": "TRY",
    "environment": "live",
    "restaurant": {
      "id": "rst_123",
      "name": "Pilavcınız Bodrum"
    },
    "orders": {
      "total": 42,
      "delivered": 38,
      "cancelled": 3,
      "open": 1
    },
    "sales": {
      "itemsGross": 11470,
      "discounts": 640,
      "deliveryFees": 380,
      "serviceFees": 380,
      "collected": 11590,
      "receiptTotal": 11210
    },
    "byPaymentMethod": [
      {
        "method": "CASH_ON_DELIVERY",
        "label": "Kapıda nakit",
        "okcPaymentType": "NAKIT",
        "count": 15,
        "amount": 4310
      },
      {
        "method": "CARD_ON_DELIVERY",
        "label": "Kapıda kart",
        "okcPaymentType": "KREDI_KARTI",
        "count": 18,
        "amount": 5640
      },
      {
        "method": "MULTINET",
        "label": "Multinet",
        "okcPaymentType": "YEMEK_KARTI",
        "count": 5,
        "amount": 1640
      }
    ],
    "vat": [
      {
        "rate": 10,
        "base": 9845.45,
        "vat": 984.55,
        "gross": 10830
      },
      {
        "rate": 20,
        "base": 316.67,
        "vat": 63.33,
        "gross": 380
      }
    ],
    "vatTotal": 1047.88,
    "platform": {
      "commission": 912,
      "platformFee": 380,
      "restaurantNet": 9848
    },
    "fiscal": {
      "issued": 37,
      "missing": [
        {
          "id": "cmv3k2q9x0009abcd",
          "orderNumber": "BTE-5Y0H2001"
        }
      ]
    }
  }
}

Uç referansı

Tam tanım: /api/v1/openapi.json (OpenAPI 3.1 — Postman, Insomnia veya Swagger Editor’e içe aktarın; istemci kodu üretebilirsiniz).

get/me· Hesap

Anahtar bilgisi

Anahtarın bağlı olduğu restoranı, ortamı (live/sandbox), yetkileri ve webhook ayarını döner. Bağlantı testi için idealdir.

{
  "data": {
    "restaurant": {
      "id": "rst_123",
      "name": "Pilavcınız Bodrum"
    },
    "environment": "sandbox",
    "apiVersion": "2026-10-01",
    "client": {
      "id": "cli_1",
      "name": "Logo POS",
      "scopes": [
        "orders:read",
        "orders:write"
      ],
      "webhookUrl": "https://pos.ornek.com/btk",
      "webhookEvents": []
    }
  }
}

Hata kodları: 401

get/orders· Siparişler

Siparişleri listele

Senkronizasyon için updatedAt artan sırada döner. Son aldığınız kaydın zamanını updatedSince ile, sayfalar arasında cursor ile ilerleyin. Webhook kaçırılsa bile bu uçla düzenli (ör. 60 sn) yoklama yaparak eksiksiz senkron kalabilirsiniz. Yetki: orders:read.

ParametreYerAçıklama
statusqueryVirgülle ayrılmış durumlar, ör. RESTAURANT_PENDING,PREPARING
updatedSincequeryISO 8601 zaman; bu andan sonra değişenler
limitqueryinteger
cursorqueryÖnceki yanıttaki nextCursor
{
  "data": [
    {
      "id": "cmv3k2q9x0001abcd",
      "orderNumber": "BTE-5Y0H1938",
      "environment": "live",
      "status": "RESTAURANT_PENDING",
      "statusLabel": "Restoran Onayı Bekleniyor",
      "createdAt": "2026-10-16T12:30:00.000Z",
      "updatedAt": "2026-10-16T12:30:00.000Z",
      "scheduledFor": null,
      "estimatedDeliveryAt": null,
      "delay": null,
      "customer": {
        "name": "Ayşe Yılmaz",
        "phone": "05551112233"
      },
      "address": {
        "label": "Ev",
        "fullAddress": "Caferağa Mah. Moda Cad. No: 12 Daire: 4, Kadıköy/İstanbul",
        "city": "İstanbul",
        "district": "Kadıköy",
        "neighborhood": "Caferağa",
        "street": "Moda Cad.",
        "buildingNo": "12",
        "floor": "2",
        "doorNo": "4",
        "directions": "Zil bozuk, arayın",
        "latitude": 40.987,
        "longitude": 29.026
      },
      "items": [
        {
          "id": "cmv3k2qa0002abcd",
          "menuItemId": "cmmenu0001",
          "name": "Tavuklu Pilav",
          "quantity": 2,
          "unitPrice": 120,
          "totalPrice": 250,
          "vatRate": 10,
          "note": "Az acılı",
          "options": [
            {
              "label": "Büyük porsiyon",
              "extraPrice": 5
            }
          ],
          "extras": [],
          "removedIngredients": [
            "Soğan"
          ]
        },
        {
          "id": "cmv3k2qa0003abcd",
          "menuItemId": "cmmenu0002",
          "name": "Ayran",
          "quantity": 2,
          "unitPrice": 25,
          "totalPrice": 50,
          "vatRate": 10,
          "note": null,
          "options": [],
          "extras": [],
          "removedIngredients": []
        }
      ],
      "payment": {
        "method": "CASH_ON_DELIVERY",
        "methodLabel": "Kapıda nakit",
        "paidOnline": false,
        "status": "PENDING"
      },
      "totals": {
        "subtotal": 300,
        "discount": 30,
        "deliveryFee": 20,
        "serviceFee": 10,
        "total": 300,
        "currency": "TRY"
      },
      "delivery": {
        "method": "own",
        "leaveAtDoor": false
      },
      "customerNote": "Kapıya bırakmayın",
      "cancellation": null,
      "accounting": {
        "commission": 24,
        "platformFee": 10,
        "restaurantNet": 246
      },
      "fiscal": null,
      "history": [
        {
          "status": "RESTAURANT_PENDING",
          "at": "2026-10-16T12:30:00.000Z",
          "note": "Restoran onayı bekleniyor"
        }
      ]
    }
  ],
  "nextCursor": null
}

Hata kodları: 401, 403, 422, 429

get/orders/{id}· Siparişler

Sipariş detayı

Ürünler, seçenekler, çıkarılan malzemeler, adres, ödeme, KDV oranları ve tutarlar. Yetki: orders:read.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "data": {
    "id": "cmv3k2q9x0001abcd",
    "orderNumber": "BTE-5Y0H1938",
    "environment": "live",
    "status": "RESTAURANT_PENDING",
    "statusLabel": "Restoran Onayı Bekleniyor",
    "createdAt": "2026-10-16T12:30:00.000Z",
    "updatedAt": "2026-10-16T12:30:00.000Z",
    "scheduledFor": null,
    "estimatedDeliveryAt": null,
    "delay": null,
    "customer": {
      "name": "Ayşe Yılmaz",
      "phone": "05551112233"
    },
    "address": {
      "label": "Ev",
      "fullAddress": "Caferağa Mah. Moda Cad. No: 12 Daire: 4, Kadıköy/İstanbul",
      "city": "İstanbul",
      "district": "Kadıköy",
      "neighborhood": "Caferağa",
      "street": "Moda Cad.",
      "buildingNo": "12",
      "floor": "2",
      "doorNo": "4",
      "directions": "Zil bozuk, arayın",
      "latitude": 40.987,
      "longitude": 29.026
    },
    "items": [
      {
        "id": "cmv3k2qa0002abcd",
        "menuItemId": "cmmenu0001",
        "name": "Tavuklu Pilav",
        "quantity": 2,
        "unitPrice": 120,
        "totalPrice": 250,
        "vatRate": 10,
        "note": "Az acılı",
        "options": [
          {
            "label": "Büyük porsiyon",
            "extraPrice": 5
          }
        ],
        "extras": [],
        "removedIngredients": [
          "Soğan"
        ]
      },
      {
        "id": "cmv3k2qa0003abcd",
        "menuItemId": "cmmenu0002",
        "name": "Ayran",
        "quantity": 2,
        "unitPrice": 25,
        "totalPrice": 50,
        "vatRate": 10,
        "note": null,
        "options": [],
        "extras": [],
        "removedIngredients": []
      }
    ],
    "payment": {
      "method": "CASH_ON_DELIVERY",
      "methodLabel": "Kapıda nakit",
      "paidOnline": false,
      "status": "PENDING"
    },
    "totals": {
      "subtotal": 300,
      "discount": 30,
      "deliveryFee": 20,
      "serviceFee": 10,
      "total": 300,
      "currency": "TRY"
    },
    "delivery": {
      "method": "own",
      "leaveAtDoor": false
    },
    "customerNote": "Kapıya bırakmayın",
    "cancellation": null,
    "accounting": {
      "commission": 24,
      "platformFee": 10,
      "restaurantNet": 246
    },
    "fiscal": null,
    "history": [
      {
        "status": "RESTAURANT_PENDING",
        "at": "2026-10-16T12:30:00.000Z",
        "note": "Restoran onayı bekleniyor"
      }
    ]
  }
}

Hata kodları: 401, 403, 404

post/orders/{id}/accept· Siparişler

Siparişi onayla

RESTAURANT_PENDING → RESTAURANT_ACCEPTED. Canlıda kontör düşer, müşteriye bildirim gider ve tahmini teslimat hesaplanır. Aynı istek tekrar gönderilirse (sipariş zaten onaylıysa) 200 ile mevcut hali döner — güvenle yeniden deneyebilirsiniz. Yetki: orders:write.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "deliveryMethod": "own"
}

Hata kodları: 401, 403, 404, 409

post/orders/{id}/reject· Siparişler

Siparişi reddet

Neden kodu zorunludur: OUT_OF_STOCK (Ürün tükendi), TOO_BUSY (Restoran çok yoğun), CLOSING (Kapanış saatine yakın), OUT_OF_ZONE (Adres teslimat bölgesi dışında), CUSTOMER_UNREACHABLE (Müşteriye ulaşılamadı / şüpheli sipariş), OTHER (Diğer). Reddedilen siparişte kontör düşmez. Yetki: orders:write.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "reasonCode": "OUT_OF_STOCK",
  "note": "Tavuk kalmadı"
}

Hata kodları: 401, 403, 404, 409, 422

post/orders/{id}/status· Siparişler

Hazırlık / yola çıktı / teslim edildi

İzinli geçişler: RESTAURANT_ACCEPTED→PREPARING→READY_FOR_PICKUP→ON_THE_WAY→DELIVERED. Paketçiniz kuryesi seçildiyse READY_FOR_PICKUP sonrası kurye adımları platformdan gelir. Geçersiz geçişte 409 invalid_transition ve details.allowed döner. Yetki: orders:write.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "status": "PREPARING"
}

Hata kodları: 401, 403, 404, 409, 422

post/orders/{id}/delay· Siparişler

Gecikme bildir

Müşteriye restoran adına özür mesajı gider ve tahmini teslimat ileri alınır (toplam en fazla 90 dk). Neden kodları: WEATHER (Hava muhalefeti), BUSY (Yoğunluk), TRAFFIC (Trafik), COURIER (Kurye gecikmesi), KITCHEN (Hazırlık uzadı). Yetki: orders:write.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "reasonCode": "WEATHER",
  "minutes": 20
}

Hata kodları: 401, 403, 404, 422

get/orders/{id}/fiscal· Mali belge

Yazar kasa / e-Arşiv fiş gövdesi

Fişe basılacak satırlar (KDV dahil), indirim, KDV kırılımı, ÖKC ödeme tipi ve müşteriden tahsil edilecek tutar. Platform hizmet bedeli restoran fişine girmez. Yetki: orders:read.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "data": {
    "orderId": "cmv3k2q9x0001abcd",
    "orderNumber": "BTE-5Y0H1938",
    "currency": "TRY",
    "pricesIncludeVat": true,
    "lines": [
      {
        "menuItemId": "cmmenu0001",
        "name": "Tavuklu Pilav",
        "quantity": 2,
        "unitPrice": 125,
        "total": 250,
        "vatRate": 10
      },
      {
        "menuItemId": "cmmenu0002",
        "name": "Ayran",
        "quantity": 2,
        "unitPrice": 25,
        "total": 50,
        "vatRate": 10
      },
      {
        "menuItemId": "DELIVERY",
        "name": "Teslimat ücreti",
        "quantity": 1,
        "unitPrice": 20,
        "total": 20,
        "vatRate": 20
      }
    ],
    "discount": {
      "amount": 30,
      "allocation": "proportional_to_items"
    },
    "vatSummary": [
      {
        "rate": 10,
        "base": 245.45,
        "vat": 24.55,
        "gross": 270
      },
      {
        "rate": 20,
        "base": 16.67,
        "vat": 3.33,
        "gross": 20
      }
    ],
    "receiptTotal": 290,
    "vatTotal": 27.88,
    "payment": {
      "method": "CASH_ON_DELIVERY",
      "okcPaymentType": "NAKIT",
      "paidOnline": false,
      "collectFromCustomer": 300
    },
    "platformServiceFee": {
      "amount": 10,
      "note": "Platform hizmet bedeli restoran fişine yazılmaz; Bir Tıkla Yemek tarafından faturalanır."
    },
    "customer": {
      "name": "Ayşe Yılmaz",
      "phone": "05551112233"
    },
    "alreadyIssued": null
  }
}

Hata kodları: 401, 403, 404

post/orders/{id}/fiscal· Mali belge

Kesilen mali belgeyi bildir

ÖKC fişi, e-Arşiv veya e-Fatura kesildikten sonra belge numarasını bildirin; gün sonu raporunda fiscal.missing listesinden düşer. Aynı belge no ile tekrar istek 200 (idempotent), farklı belge 409 döner. totalAmount/vatTotal gönderilmezse fiş gövdesinden hesaplanır. Yetki: fiscal:write.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "type": "OKC_RECEIPT",
  "documentNumber": "0042",
  "zReportNo": "1187",
  "ekuNo": "3",
  "issuedAt": "2026-10-16T13:05:00+03:00"
}

Hata kodları: 401, 403, 404, 409, 422

get/accounting/daily· Muhasebe

Günlük satış / KDV raporu

İstanbul saatine göre günün siparişleri: teslim edilen ciro, ödeme yöntemi ve ÖKC ödeme tipi kırılımı, KDV matrah/tutar, platform komisyonu ve restoran neti, mali belgesi eksik siparişler. Z raporu ve muhasebe kaydı mutabakatı için. Yetki: accounting:read.

ParametreYerAçıklama
datequeryYYYY-AA-GG (varsayılan: bugün)
{
  "data": {
    "date": "2026-10-16",
    "currency": "TRY",
    "environment": "live",
    "restaurant": {
      "id": "rst_123",
      "name": "Pilavcınız Bodrum"
    },
    "orders": {
      "total": 42,
      "delivered": 38,
      "cancelled": 3,
      "open": 1
    },
    "sales": {
      "itemsGross": 11470,
      "discounts": 640,
      "deliveryFees": 380,
      "serviceFees": 380,
      "collected": 11590,
      "receiptTotal": 11210
    },
    "byPaymentMethod": [
      {
        "method": "CASH_ON_DELIVERY",
        "label": "Kapıda nakit",
        "okcPaymentType": "NAKIT",
        "count": 15,
        "amount": 4310
      },
      {
        "method": "CARD_ON_DELIVERY",
        "label": "Kapıda kart",
        "okcPaymentType": "KREDI_KARTI",
        "count": 18,
        "amount": 5640
      },
      {
        "method": "MULTINET",
        "label": "Multinet",
        "okcPaymentType": "YEMEK_KARTI",
        "count": 5,
        "amount": 1640
      }
    ],
    "vat": [
      {
        "rate": 10,
        "base": 9845.45,
        "vat": 984.55,
        "gross": 10830
      },
      {
        "rate": 20,
        "base": 316.67,
        "vat": 63.33,
        "gross": 380
      }
    ],
    "vatTotal": 1047.88,
    "platform": {
      "commission": 912,
      "platformFee": 380,
      "restaurantNet": 9848
    },
    "fiscal": {
      "issued": 37,
      "missing": [
        {
          "id": "cmv3k2q9x0009abcd",
          "orderNumber": "BTE-5Y0H2001"
        }
      ]
    }
  }
}

Hata kodları: 401, 403, 422

get/menu· Menü

Menü, fiyat ve KDV

POS ürün eşleştirmesi için ürün kimlikleri, fiyatlar (KDV dahil), KDV oranı ve stok durumu. Yetki: menu:read.

{
  "data": [
    {
      "id": "cmmenu0001",
      "name": "Tavuklu Pilav",
      "description": null,
      "category": {
        "id": "cat1",
        "name": "Pilavlar"
      },
      "price": 120,
      "discountedPrice": null,
      "vatRate": 10,
      "isAvailable": true,
      "imageUrl": null
    }
  ]
}

Hata kodları: 401, 403

patch/menu/items/{id}· Menü

Ürün fiyat / KDV / stok güncelle

Sandbox'ta doğrulanır ama kaydedilmez (persisted: false). Yetki: menu:write.

ParametreYerAçıklama
id*pathstring
{
  "isAvailable": false
}

Hata kodları: 401, 403, 404, 422

post/menu/availability· Menü

Toplu stok senkronizasyonu

POS'ta tükenen / tekrar satışa açılan ürünleri tek istekte bildirin (en fazla 500). Yetki: menu:write.

{
  "items": [
    {
      "id": "cmmenu0001",
      "isAvailable": false
    },
    {
      "id": "cmmenu0002",
      "isAvailable": true
    }
  ]
}
{
  "data": {
    "updated": 2,
    "unknown": [],
    "persisted": true
  }
}

Hata kodları: 401, 403, 422

post/webhooks/test· Webhook

Test olayı gönder

Tanımlı webhook adresinize imzalı webhook.test olayı gönderir.

{
  "data": {
    "queued": true,
    "deliveryId": "cmdel0001"
  }
}

Hata kodları: 401, 422

get/webhooks/deliveries· Webhook

Webhook teslim günlüğü

Son 100 teslimat: durum, deneme sayısı, son HTTP kodu ve hata.

Hata kodları: 401

post/sandbox/orders· Sandbox

Test siparişi oluştur

Yalnızca btk_test_ anahtarıyla. Restoranın gerçek menüsünden test siparişi oluşturur ve order.created webhook'u gönderir. Gövde boşsa rastgele ürün, müşteri ve ödeme yöntemi seçilir.

{
  "items": [
    {
      "menuItemId": "cmmenu0001",
      "quantity": 2
    }
  ],
  "paymentMethod": "CASH_ON_DELIVERY",
  "deliveryFee": 20
}

Hata kodları: 401, 403, 422

post/sandbox/orders/{id}/simulate· Sandbox

Platform olayı simüle et

Platform tarafında gerçekleşen olayları taklit eder: customer_cancelled (onay bekleyen/onaylı), courier_assigned (hazır), courier_picked_up, delivered. İlgili webhook gönderilir.

ParametreYerAçıklama
id*pathSipariş kimliği (id) veya sipariş numarası (orderNumber)
{
  "event": "courier_assigned"
}

Hata kodları: 401, 403, 404, 409

Hata kodları

{
  "error": {
    "code": "invalid_transition",
    "message": "Sipariş 'Restoran Onayı Bekleniyor' durumundan 'Teslim Edildi' durumuna geçirilemez.",
    "details": {
      "currentStatus": "RESTAURANT_PENDING",
      "allowed": [
        "RESTAURANT_ACCEPTED",
        "RESTAURANT_REJECTED"
      ]
    },
    "requestId": "req_9f2c1a7b3d4e5f60"
  }
}
HTTPcodeAnlamı
400invalid_requestGeçersiz JSON
401unauthorizedAnahtar yok, hatalı veya iptal edilmiş
403forbiddenAnahtarın bu yetkisi (scope) yok, sandbox'a özel uç canlı anahtarla çağrıldı veya restoran aktif değil
404not_foundSipariş/ürün yok ya da bu restorana / bu ortama ait değil
409invalid_transitionSiparişin mevcut durumundan bu duruma geçilemez (details.allowed izinli geçişleri listeler)
409conflictEşzamanlı güncelleme veya farklı bir mali belge zaten kayıtlı
422invalid_requestGövde doğrulama hatası (details alan bazında açıklar)
429rate_limitedDakikada 120 isteği aştınız; Retry-After kadar bekleyin
500internal_errorBeklenmeyen hata — requestId ile destek ekibine yazın

Canlıya geçiş kontrol listesi

  • Sandbox'ta onay, ret, tüm hazırlık adımları, gecikme ve simülasyonlar denendi
  • Webhook imzası doğrulanıyor, olaylar event.id ile tekilleştiriliyor
  • Webhook 10 sn içinde 2xx dönüyor; ağır iş kuyruğa alınıyor
  • Webhook'a ek olarak updatedSince ile periyodik yoklama yapılıyor
  • 409 invalid_transition ve 429 rate_limited doğru işleniyor
  • ÖKC / e-Arşiv belge numarası POST /orders/{id}/fiscal ile bildiriliyor
  • Gün sonu raporunda fiscal.missing listesi boş
  • Canlı anahtar yalnızca sunucuda, şifreli olarak saklanıyor

Entegrasyon ortaklığı ve destek

POS / muhasebe yazılımı firmasıysanız ve birden çok restorana entegrasyon sunacaksanız, test restoranı ve teknik destek için destek@birtiklayemek.com adresine yazın. Sorunlarda BTK-Request-Id ve BTK-Delivery-Id değerlerini paylaşın.