MekanBook developer platform
Connect your venue's menu, orders, reservations, loyalty accounts and events to your own software, accounting and CRM systems or automation tools.
REST API
JSON, cursor pagination, per-key scopes and rate limits.
Webhooks
Signed notifications on events; automatic retries for up to 24 h.
MCP
Let your AI assistant query venue data read-only.
Base URL: https://www.mekanbook.com/api/partner/v1 · Version 1.0.0
If you build POS software (pushing orders to the POS, payments at the till), see also the POS Connector API.
Authentication
The venue owner or manager creates a key in Panel › Settings › Developer. The key is shown once; only its hash is stored. Send it with every request:
Authorization: Bearer mbp_xxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- Never ship the key in client-side code (browser, mobile app); keep it in a server-side environment variable.
- An optional IP allowlist and a per-key rate limit (default 120/min) can be set.
- Rotating a key revokes the old one immediately. All key operations are audited.
Scopes
| Scope | Description |
|---|---|
menu:read | Read the menu |
menu:write | Update menu prices and availability |
orders:read | Read orders |
orders:write | Update order status |
reservations:read | Read reservations |
reservations:write | Create reservations and change status |
loyalty:read | Read loyalty accounts |
loyalty:write | Add/remove loyalty points |
customers:read | Guest list (masked) |
events:read | Read events |
webhooks:manage | Manage webhook endpoints |
ecommerce:read | Online mağaza: müşteri bakiyesi ve teklif |
ecommerce:write | Online mağaza: hesap bağlama, puan kazandırma/kullanma, iade |
Privacy (KVKK): the guest list is masked (first name + initial). Phone and email are returned only for guests with marketing consent, partially hidden. Reservation contact details are available only under the reservations scope, for the venue's own operations.
Endpoints
| Method | Path | Summary | Scope |
|---|---|---|---|
| GET | /me | Current key and venue | |
| GET | /menu | Full menu (menus › categories › items) | menu:read |
| PATCH | /menu/items | Bulk update prices/availability (max 500). Price changes are logged. | menu:write |
| GET | /menu/items/{id} | One menu item | menu:read |
| PATCH | /menu/items/{id} | Update price and/or availability | menu:write |
| GET | /orders | Table orders (newest first) | orders:read |
| GET | /orders/{id} | One order | orders:read |
| POST | /orders/{id}/status | Move order lines to a new status (accepted → preparing → ready → served) | orders:write |
| GET | /reservations | Reservations | reservations:read |
| POST | /reservations | Create a confirmed reservation (staff channel; availability rules apply) | reservations:write |
| GET | /reservations/{id} | One reservation | reservations:read |
| POST | /reservations/{id}/status | Change reservation status (declined/cancelled_by_venue require reason; deposits are refunded automatically) | reservations:write |
| GET | /loyalty/accounts | Loyalty accounts (customer masked) | loyalty:read |
| GET | /loyalty/accounts/{id} | Loyalty account with last 50 transactions | loyalty:read |
| POST | /loyalty/accounts/{id}/adjust | Add or remove points (audited) | loyalty:write |
| GET | /customers | Guest book (masked; contact only with marketing consent) | customers:read |
| GET | /events | Published events (upcoming by default) | events:read |
| GET | /webhooks | Webhook endpoints | webhooks:manage |
| POST | /webhooks | Create endpoint. The signing secret is returned once. | webhooks:manage |
| DELETE | /webhooks/{id} | Delete endpoint | webhooks:manage |
| GET | /ecommerce/ping | Online store connection test and rules | ecommerce:read |
| POST | /ecommerce/links | Ask the customer to link their MekanBook account (code + approval link e-mailed; response never reveals whether an account exists) | ecommerce:write |
| GET | /ecommerce/links/{id} | Link request status (approved → customer_ref) | ecommerce:read |
| POST | /ecommerce/links/{id}/verify | Verify the 6-digit code the customer typed (max 5 attempts) | ecommerce:write |
| GET | /ecommerce/customers/{ref} | Balance (points, cashback, stamps, rewards) for a linked customer | ecommerce:read |
| DELETE | /ecommerce/customers/{ref} | Unlink the customer (consent withdrawn at the store) | ecommerce:write |
| POST | /ecommerce/quote | Redeemable discount for a basket (respects max %, min order, min points) | ecommerce:read |
| POST | /ecommerce/redemptions | Reserve points (deducted now, held 30 minutes). Idempotency-Key required. | ecommerce:write |
| GET | /ecommerce/redemptions/{id} | Redemption | ecommerce:read |
| POST | /ecommerce/redemptions/{id}/confirm | Confirm when the order is paid (re-deducts if the hold expired and balance allows; else 409 redemption_expired) | ecommerce:write |
| POST | /ecommerce/redemptions/{id}/cancel | Release a reserved redemption (points return to the same ledger rows) | ecommerce:write |
| POST | /ecommerce/orders | Paid order: award points once per order_ref (amount = paid, excl. shipping) | ecommerce:write |
| GET | /ecommerce/orders/{ref} | Order | ecommerce:read |
| POST | /ecommerce/orders/{ref}/refund | Refund: cumulative refunded_total; points/cashback reversed proportionally; full refund returns used points | ecommerce:write |
| POST | /ecommerce/orders/{ref}/cancel | Cancel: reverse all earned points and return used points | ecommerce:write |
| GET | /ecommerce/transactions | Recent online ledger entries for this store | ecommerce:read |
Amounts are integers in minor units (24500 = 245.00 TRY). Times are ISO 8601 (UTC). Price changes are written to the price history and audit log; the price update date is shown on the menu as required by regulation.
Examples
Update an item price
curl -X PATCH https://www.mekanbook.com/api/partner/v1/menu/items/123 \
-H "Authorization: Bearer $MEKANBOOK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"price": 24500, "available": true}'
// Node 18+ (fetch yerleşik) — or: import { MekanBook } from '@mekanbook/partner'
const res = await fetch('https://www.mekanbook.com/api/partner/v1/menu/items/123', {
method: 'PATCH',
headers: { Authorization: `Bearer ${process.env.MEKANBOOK_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ price: 24500, available: true }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log((await res.json()).data);
import os, json, urllib.request
req = urllib.request.Request(
"https://www.mekanbook.com/api/partner/v1/menu/items/123",
data=json.dumps({"price": 24500, "available": True}).encode(),
method="PATCH",
headers={"Authorization": f"Bearer {os.environ['MEKANBOOK_API_KEY']}", "Content-Type": "application/json"},
)
print(json.load(urllib.request.urlopen(req))["data"])
<?php
$ch = curl_init('https://www.mekanbook.com/api/partner/v1/menu/items/123');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'PATCH',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer '.getenv('MEKANBOOK_API_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['price' => 24500, 'available' => true]),
]);
$item = json_decode(curl_exec($ch), true)['data'];
Today's reservations
curl "https://www.mekanbook.com/api/partner/v1/reservations?from=2026-11-10T00:00&to=2026-11-10T23:59&status=confirmed" \
-H "Authorization: Bearer $MEKANBOOK_API_KEY"
Create a reservation
curl -X POST https://www.mekanbook.com/api/partner/v1/reservations -H "Authorization: Bearer $MEKANBOOK_API_KEY" -H "Content-Type: application/json" \
-d '{"date":"2026-11-11","time":"20:00","party":4,"name":"Ayşe Yılmaz","phone":"+905551112233"}'
Reservations created via the API count as staff entries: confirmed immediately, no deposit; shift, capacity and closed-day rules apply.
Pagination, errors and limits
Lists are newest first. Use limit (1–100, default 50) and pass next_cursor back as cursor; null means the last page. Use updated_since to fetch changes.
{ "data": [ … ], "next_cursor": "MTIzNA==" }
{ "error": { "code": "insufficient_scope", "message": "This API key lacks the 'orders:read' scope." } }
| HTTP | code | Meaning |
|---|---|---|
| 401 | invalid_key | Missing, wrong or revoked key |
| 403 | plan_required | The venue plan does not include the developer API |
| 403 | insufficient_scope · ip_not_allowed | Scope or IP not allowed |
| 404 | not_found | Not found for this venue |
| 422 | validation_failed | Invalid input; details in fields |
| 429 | rate_limited | Rate limited; wait Retry-After seconds |
Webhooks
Register your https endpoint and events in Panel › Developer or via the API (webhooks:manage). Every delivery has the same envelope:
POST /your/endpoint
X-MekanBook-Event: reservation.created
X-MekanBook-Delivery: 2b1f0c3e-… ← use to de-duplicate
X-MekanBook-Timestamp: 1767225600
X-MekanBook-Signature: t=1767225600,v1=5f2c…
{"id":"2b1f0c3e-…","type":"reservation.created","created_at":"2026-12-31T19:00:00+00:00","venue_id":42,"data":{ … }}
Events: order.created, order.updated, reservation.created, reservation.updated, reservation.cancelled, loyalty.earned, loyalty.redeemed, loyalty.adjusted, review.created, takeaway.created, takeaway.updated, menu.updated, ecommerce.link.created, ecommerce.link.revoked · ping (test from panel)
- Respond 2xx within 10 seconds; queue the work and reply immediately.
- Failed deliveries are retried after 1 m, 5 m, 15 m, 1 h, 3 h, 6 h, 12 h and 24 h. 50 consecutive failures disable the endpoint; re-enable it in the panel.
- Only public https addresses are called (no private networks, redirects are not followed).
Signature verification
The signature is computed over the raw (unparsed) body: HMAC-SHA256(secret, "{t}.{body}"). Reject timestamps older than 5 minutes.
import crypto from 'node:crypto';
export function verify(secret, header, rawBody) {
const m = /t=(\d+),v1=([a-f0-9]{64})/.exec(header || '');
if (!m || Math.abs(Date.now() / 1000 - Number(m[1])) > 300) return false;
const expected = crypto.createHmac('sha256', secret).update(`${m[1]}.${rawBody}`).digest('hex');
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}
import hmac, hashlib, re, time
def verify(secret: str, header: str, raw_body: bytes) -> bool:
m = re.search(r"t=(\d+),v1=([a-f0-9]{64})", header or "")
if not m or abs(time.time() - int(m.group(1))) > 300:
return False
expected = hmac.new(secret.encode(), m.group(1).encode() + b"." + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, m.group(2))
<?php
function mekanbook_verify(string $secret, string $header, string $rawBody): bool {
if (! preg_match('/t=(\d+),v1=([a-f0-9]{64})/', $header, $m) || abs(time() - (int) $m[1]) > 300) {
return false;
}
return hash_equals(hash_hmac('sha256', $m[1].'.'.$rawBody, $secret), $m[2]);
}
// $ok = mekanbook_verify(getenv('MEKANBOOK_WEBHOOK_SECRET'), $_SERVER['HTTP_X_MEKANBOOK_SIGNATURE'] ?? '', file_get_contents('php://input'));
MCP server (AI assistants)
Assistants that support the Model Context Protocol (e.g. Claude, ChatGPT and MCP-capable IDEs) can query your venue data read-only: “How many covers tonight?”, “Which meze cost under 300 TL?”
| URL | https://www.mekanbook.com/mcp (Streamable HTTP, POST) |
|---|---|
| Auth | Authorization: Bearer mbp_… — tools are listed according to the key's scopes |
| Protocol | 2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26 |
| Tool | Description | Scope |
|---|---|---|
get_menu | Returns the venue menu: categories and items with current prices (kuruş), availability and last price update. | menu:read |
list_reservations | Lists reservations for a local date (default: today) with status, party size and time. Contact details are not included. | reservations:read |
get_today_stats | Today's reservation count and covers, table orders, order total (kuruş) and open checks (venue local day). | reservations:read orders:read |
search_customers | Searches the guest book by name or the last 4 digits of a phone number. Names, phones and emails are masked. | customers:read |
list_events | Lists the venue's published upcoming events (concerts, parties) with dates. | events:read |
@__raw_block_3__{{ $mcpUrl }}",
"headers": { "Authorization": "Bearer mbp_…" }
}
}
}
Give the assistant a separate read-only key (e.g. menu:read, reservations:read, events:read). Guest data is masked.
SDK
JavaScript / TypeScript
Node 18+, Deno, Bun and browsers. No dependencies; types included.
import { MekanBook } from './mekanbook-js/src/index.js';
const mb = new MekanBook({ apiKey: process.env.MEKANBOOK_API_KEY });
for await (const r of mb.paginate('/reservations', { status: 'confirmed' })) console.log(r.starts_at, r.party_size);
E-commerce loyalty
A venue's online store awards and redeems points on the same loyalty card used in the venue. The key is created in Panel › Marketing › Online store (ecommerce:read, ecommerce:write). Customers approve the link themselves with an e-mailed code; the store only sees an opaque customer_ref.
WooCommerce
Ready plugin: “Use MekanBook points” on checkout, points on completed orders, reversal on refunds, signed webhook. TR/EN.
Other platforms
No ready apps for Shopify, İkas, Ticimax, IdeaSoft, T-Soft or custom sites; integrate with the server-side API and the JS widget.
| Endpoint | Description |
|---|---|
GET /ecommerce/ping | Connection test, rules |
POST /ecommerce/links · GET /ecommerce/links/{id} · POST /ecommerce/links/{id}/verify | Consent-based account linking (e-mailed code + approval link) |
GET|DELETE /ecommerce/customers/{ref} | Balance / unlink |
POST /ecommerce/quote | Redeemable discount for a basket |
POST /ecommerce/redemptions · /{id}/confirm · /{id}/cancel | Reserve (30 min, Idempotency-Key required) → confirm / cancel |
POST /ecommerce/orders · /{ref}/refund · /{ref}/cancel | Award on paid order; proportional reversal by cumulative refunded total; cancel |
GET /ecommerce/transactions | Recent online ledger entries |
curl -X POST https://www.mekanbook.com/api/partner/v1/ecommerce/redemptions \
-H "Authorization: Bearer mbp_…" -H "Idempotency-Key: cart-8f2c" -H "Content-Type: application/json" \
-d '{"customer_ref":"mbc_…","order_total":45000,"unit":"points","points":300}'
Zapier · Make · n8n
No-code: use the tool's webhook trigger URL as a webhook endpoint in Panel › Developer, and call the API with an “HTTP request” step using your Bearer key.
- Zapier: Webhooks by Zapier › Catch Hook (trigger) → Google Sheets, Slack, email…
- Make: Webhooks › Custom webhook → HTTP › Make a request. Sample blueprint: make-blueprint.json
- n8n: Webhook node → (Code node for signature check) → HTTP Request. Sample workflow: n8n-workflow.json
Changelog
- 1.0.0 · 2026-11-26 — First release: menu, orders, reservations, loyalty, customers and events endpoints; webhooks; MCP server; JavaScript and Python SDKs.
Breaking changes ship under a new version path (/v2); v1 will not be retired without at least 12 months' notice. Что нового