Developers
Madar POS API and MCP server
Read a café's own public data: its brand and links page, branches, menu with prices in EGP, table booking times and the status of an online order. No account and no key.
- Base URL
https://api.madar-pos.cloud- Authentication
- None for paths under
/public/ - Format
- JSON over HTTPS
- OpenAPI
https://api.madar-pos.cloud/openapi.json- MCP server
https://api.madar-pos.cloud/mcp(Streamable HTTP)
What it's for
Every café or restaurant on Madar POS has public pages: a links page, a menu, online ordering, table booking and order tracking. The API behind them is open to read, so an app or an AI agent can answer questions like "what does a large latte cost at Drops?" or "is there a table for four on Friday at 7?".
Every call names one shop: by its address name (drops for
drops.madar-pos.cloud) or by its id. There is no list of all shops, on purpose:
you start from a shop you already know.
Prices are whole numbers of piastres, in Egyptian pounds: 6500 is 65.00 EGP.
Times are ISO 8601 in UTC; booking answers carry the branch's time zone.
Endpoints
All are GET, under https://api.madar-pos.cloud.
| Method | Path | Returns |
|---|---|---|
GET | /public/orgs/brand?slug={shop} | The shop's id, name, logo and colours. Pass org_id={uuid} instead of slug when you have the id. |
GET | /public/orgs/links?slug={shop} | The shop's links page in one call: brand, taglines, its buttons (order online, menu, book a table, rewards, its own links) with their addresses, social links, and branches with address, phone and directions. |
GET | /public/branches?org_id={uuid}&browse=true | The shop's active branches: id, name, and which ordering channels are on and open now. Without browse=true, only the branches that take online orders. |
GET | /public/branches/{id}/menu?channel=dine_in&preview=true | A branch's menu: categories, items with sizes, add-ons and deals. dine_in with preview=true is the read-only menu at branch prices. An ordering channel (pickup, outside, in_mall, umbrella) gives that channel's prices, and only while it is open unless preview=true. |
GET | /public/branches/{id}/booking-slots?date=YYYY-MM-DD&party_size={n} | The branch's bookable start times that day for that party size, each marked available or not, with the branch's time zone. |
GET | /public/delivery-orders/{id}/track | An online order's status, the time of each step, and its totals, by the order id in its tracking link. |
A typical path: the links page by the shop's address name gives its branches and their ids; a branch id gives the menu and the booking times.
Examples
A shop's links page and branches
curl -s 'https://api.madar-pos.cloud/public/orgs/links?slug=drops' {
"brand": { "org_id": "2f6c0d4e-…", "name": "Drops", "slug": "drops", "logo_url": "https://…", … },
"tagline_en": "…",
"items": [
{ "kind": "order", "href": "https://drops.madar-pos.cloud/order/", "channels": ["pickup"], "branch_names": ["…"] },
{ "kind": "book", "href": "https://drops.madar-pos.cloud/book/", "channels": [], "branch_names": ["…"] }
],
"socials": [{ "key": "instagram", "label": "Instagram", "url": "https://www.instagram.com/…" }],
"branches": [
{ "id": "8d1e5a2c-…", "name": "…", "address": "…", "phone": "…", "directions_url": "https://…" }
]
} A branch's menu
curl -s "https://api.madar-pos.cloud/public/branches/$BRANCH_ID/menu?channel=dine_in&preview=true" {
"categories": [{ "id": "…", "name": "Hot drinks", "name_translations": { "ar": "مشروبات سخنة" } }],
"items": [
{
"id": "…", "category_id": "…", "kind": "item", "name": "Cappuccino", "price": 6500,
"sizes": [{ "label": "Small", "price": 6500 }, { "label": "Large", "price": 8000 }],
…
}
],
"addons": [ … ],
"deals": [],
"discount": null
} Free tables on a date
curl -s "https://api.madar-pos.cloud/public/branches/$BRANCH_ID/booking-slots?date=2026-10-10&party_size=4" {
"date": "2026-10-10",
"timezone": "Africa/Cairo",
"slots": [
{ "starts_at": "2026-10-10T15:00:00Z", "available": true },
{ "starts_at": "2026-10-10T15:30:00Z", "available": false }
]
} Ordering and booking
Placing an order (POST /public/delivery-orders) or a booking
(POST /public/bookings) needs the customer's WhatsApp one-time code
(POST /public/otp/request, then POST /public/otp/verify). So an agent
should not try to finish it for them: send the person the shop's order or booking link (the
order and book items of /public/orgs/links, such as
https://drops.madar-pos.cloud/order/) and they finish there.
Limits and errors
Requests are limited per client IP. Over the limit, the answer is 429 with a
Retry-After header and a JSON body that says how long to wait:
HTTP/2 429
retry-after: 12
content-type: application/json
{"error":"Too many requests just now. This will clear in a moment.","code":"RATE_LIMITED","retry_after_seconds":12}
Every error is JSON with an error message. An address name that isn't a shop (or
a shop that is switched off) answers 404:
curl -si 'https://api.madar-pos.cloud/public/orgs/brand?slug=no-such-shop'
HTTP/2 404
content-type: application/json
{"error":"Not found"} Cache what you read, and don't crawl.
OpenAPI
The public part of the API, as OpenAPI 3.1: https://api.madar-pos.cloud/openapi.json
(get.madar-pos.cloud/openapi.json redirects there).
MCP server
The same data as tools for AI assistants, over the Model Context Protocol. Read-only, no authentication, and the same per-IP rate limits as the API.
- Endpoint
https://api.madar-pos.cloud/mcp- Transport
- Streamable HTTP, stateless: each
POSTcarries one JSON-RPC message and is answered withapplication/json. No session id and no SSE stream;GET /mcpanswers405. - Protocol versions
2025-06-18(default),2025-03-26,2024-11-05- Authentication
- None
- Manifest
https://get.madar-pos.cloud/.well-known/mcp.json- Server card
https://api.madar-pos.cloud/.well-known/mcp/server-card.json
Tools
| Tool | Input | Returns |
|---|---|---|
get_shop | shop: string | The shop's name, tagline, links (order online, menu, book a table, rewards), social links, and branches (id, name, address, phone, directions). |
get_menu | shop: string, branch_id?: string (uuid) | The menu: categories and items with prices in EGP, sizes where an item has them. Without branch_id, the shop's first branch. |
get_booking_slots | branch_id: string (uuid), date: string (YYYY-MM-DD), party_size: integer | The branch's bookable times that day, and which are available. |
track_order | order_id: string (uuid) | An online order's status and timeline, without customer details. |
about_madar | none | What Madar POS is, its plans and monthly prices per branch, and how to reach sales. |
Try it
Start a session (optional, since the server keeps no state):
curl -s https://api.madar-pos.cloud/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0"}}}' {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{"listChanged":false}},"serverInfo":{"name":"madar-pos","title":"Madar POS","version":"…"},"instructions":"…"}} List the tools:
curl -s https://api.madar-pos.cloud/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' Call one:
curl -s https://api.madar-pos.cloud/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_menu","arguments":{"shop":"drops"}}}' Contact
Questions about the API or the MCP server, or something you need from it: email shawket.4@icloud.com or WhatsApp +20 121 111 6899.