{
  "openapi": "3.1.0",
  "info": {
    "title": "MezbanPOS Public API",
    "version": "1.0",
    "summary": "Integrate your website, mobile app, kiosk or third-party service with your MezbanPOS restaurant.",
    "description": "All requests and responses use JSON. **All timestamps are Unix milliseconds** (ms since epoch).\nAll prices are in **PKR**.\n\n## Authentication\nEvery request must include your API key in the `Authorization` header:\n\n```\nAuthorization: Bearer YOUR_API_KEY\n```\n\nFind your API key in your MezbanPOS dashboard under **Settings → Integrations → API Key**.\n\n> **Keep your API key secret.** It has full access to your restaurant data. If it is ever\n> compromised, regenerate it from the dashboard. Never put it in browser or mobile app code\n> that customers can read; call the API from your own server.\n\n## Branch context\nIf your account has multiple branches, pass the branch you want to operate on in the\n`X-Branch-Id` header (IDs come from `GET /branches`). If omitted, requests default to your\n**Main Branch**.\n\n## Rate limiting\n120 requests per minute per API key. Every response includes `X-RateLimit-Limit`,\n`X-RateLimit-Remaining` and `X-RateLimit-Reset`. When the limit is exceeded the API returns\n**429 Too Many Requests**.\n\n## Errors\nAll errors return a JSON body with an `error` field, for example `{\"error\": \"Item not found\"}`.\n\n| Status | Meaning |\n|---|---|\n| `400` | Bad request: invalid or missing fields |\n| `401` | Missing or invalid API key |\n| `402` | Subscription expired |\n| `403` | Action not allowed (for example online ordering is switched off, or a plan limit is reached) |\n| `404` | Resource not found |\n| `429` | Rate limit exceeded |\n| `500` | Internal server error |\n\n## Typical flows\n**Online ordering website**\n1. `GET /settings`: if `online_ordering_enabled` is `\"0\"`, hide the checkout.\n2. `GET /menu` on page load and show categories and items.\n3. The customer builds a cart in your frontend (no API calls needed).\n4. Optional: `POST /discount-codes/apply` to validate a promo code.\n5. `POST /orders` with the cart. The order appears on the POS and kitchen display immediately.\n6. Show the returned `orderNumber`, then poll `GET /orders/{id}` every 15–30 seconds,\n   or share the public tracking link (`GET /public/{slug}/order/{orderNumber}`).\n\n**Delivery app**\n1. `POST /orders` (type `delivery`)\n2. `GET /riders` and pick a rider\n3. `POST /riders/assignments`\n4. `PATCH /riders/assignments/{id}` with `{\"status\": \"picked_up\"}`\n5. `PATCH /riders/assignments/{id}` with `{\"status\": \"delivered\", \"codCollected\": 1750}`\n6. `PATCH /orders/{id}/status` with `{\"status\": \"done\"}`\n7. `POST /riders/settlements` at the end of the shift\n\nNeed help? Email **support@mezbanpos.com** or use the support chat in your dashboard.\n",
    "contact": {
      "name": "MezbanPOS Support",
      "email": "support@mezbanpos.com",
      "url": "https://mezbanpos.com/support.php"
    },
    "termsOfService": "https://mezbanpos.com/terms.php"
  },
  "servers": [
    {
      "url": "https://app.mezbanpos.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Menu",
      "description": "Read your restaurant's menu. Menu data is **read-only** through the API; manage it from the MezbanPOS dashboard."
    },
    {
      "name": "Orders",
      "description": "Create and track orders from your external platform."
    },
    {
      "name": "Customers",
      "description": "Look up and manage your customer database for loyalty programs, CRM, or delivery apps."
    },
    {
      "name": "Branches",
      "description": "List your restaurant's locations. Pass the chosen branch's `id` as `X-Branch-Id` on later requests to scope them to that location."
    },
    {
      "name": "Discount Codes",
      "description": "Validate a promo code before submitting an order."
    },
    {
      "name": "Public Order Tracking",
      "description": "Let customers check their order status without exposing your API key. No authentication required."
    },
    {
      "name": "Settings",
      "description": "Check whether the restaurant is accepting orders before showing the checkout."
    },
    {
      "name": "Tables",
      "description": "Tables and their occupancy, for QR-code-at-table ordering."
    },
    {
      "name": "Email Receipts",
      "description": "Send a receipt to a customer's email. Requires email receipts to be configured under **Settings → Email Receipts**."
    },
    {
      "name": "Inventory",
      "description": "Check and adjust stock levels for menu items, for supplier portals and warehouse integrations."
    },
    {
      "name": "Delivery Drivers",
      "description": "Manage riders and the delivery dispatch workflow — assign orders to riders, track pickups and deliveries, and settle accounts."
    }
  ],
  "paths": {
    "/menu": {
      "get": {
        "tags": [
          "Menu"
        ],
        "operationId": "getMenu",
        "summary": "Get the full menu",
        "description": "Returns the full menu — categories, items (with variants and modifiers), and combo deals.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "The full menu.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Menu"
                },
                "example": {
                  "categories": [
                    {
                      "id": 1,
                      "name": "Burgers",
                      "color": "#ef4444",
                      "sortOrder": 0,
                      "taxRate": null
                    }
                  ],
                  "items": [
                    {
                      "id": 10,
                      "categoryId": 1,
                      "name": "Classic Burger",
                      "description": "100% beef patty with lettuce and tomato",
                      "basePrice": 650,
                      "imageUrl": "https://app.mezbanpos.com/uploads/menu-images/burger.jpg",
                      "taxRate": null,
                      "sortOrder": 0,
                      "variants": [
                        {
                          "id": 5,
                          "name": "Single",
                          "priceModifier": 0
                        },
                        {
                          "id": 6,
                          "name": "Double",
                          "priceModifier": 150
                        }
                      ],
                      "modifiers": [
                        {
                          "id": 3,
                          "name": "Extra Cheese",
                          "extraPrice": 50,
                          "isRequired": false
                        },
                        {
                          "id": 4,
                          "name": "No Onion",
                          "extraPrice": 0,
                          "isRequired": false
                        }
                      ]
                    }
                  ],
                  "combos": [
                    {
                      "id": 2,
                      "name": "Burger Meal",
                      "description": "Burger + Fries + Drink",
                      "discountPrice": 999,
                      "items": [
                        {
                          "menuItemId": 10,
                          "variantId": null,
                          "quantity": 1,
                          "allowVariantSelection": true,
                          "sortOrder": 0
                        },
                        {
                          "menuItemId": 15,
                          "variantId": null,
                          "quantity": 1,
                          "allowVariantSelection": false,
                          "sortOrder": 1
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/menu/categories": {
      "get": {
        "tags": [
          "Menu"
        ],
        "operationId": "listCategories",
        "summary": "List categories",
        "description": "Returns only the list of active categories.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Active categories.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Category"
                  }
                },
                "example": [
                  {
                    "id": 1,
                    "name": "Burgers",
                    "color": "#ef4444",
                    "sortOrder": 0,
                    "taxRate": null
                  },
                  {
                    "id": 2,
                    "name": "Drinks",
                    "color": "#3b82f6",
                    "sortOrder": 1,
                    "taxRate": null
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/menu/items": {
      "get": {
        "tags": [
          "Menu"
        ],
        "operationId": "listMenuItems",
        "summary": "List menu items",
        "description": "Returns all active items. Filter by category with `category_id`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "name": "category_id",
            "in": "query",
            "description": "Return only items in this category.",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Array of item objects (same shape as `items` in `GET /menu`).",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MenuItem"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/menu/items/{id}": {
      "get": {
        "tags": [
          "Menu"
        ],
        "operationId": "getMenuItem",
        "summary": "Get a menu item",
        "description": "Returns a single menu item with its variants and modifiers.\n\n**Pricing:** the final price of an item is\n`basePrice + variant.priceModifier + sum(modifier.extraPrice)`.\nExample: Classic Burger, Double, with Extra Cheese = 650 + 150 + 50 = **Rs 850**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "The menu item.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MenuItem"
                },
                "example": {
                  "id": 10,
                  "categoryId": 1,
                  "name": "Classic Burger",
                  "description": "100% beef patty with lettuce and tomato",
                  "basePrice": 650,
                  "imageUrl": "https://app.mezbanpos.com/uploads/menu-images/burger.jpg",
                  "taxRate": null,
                  "sortOrder": 0,
                  "variants": [
                    {
                      "id": 5,
                      "name": "Single",
                      "priceModifier": 0
                    },
                    {
                      "id": 6,
                      "name": "Double",
                      "priceModifier": 150
                    }
                  ],
                  "modifiers": [
                    {
                      "id": 3,
                      "name": "Extra Cheese",
                      "extraPrice": 50,
                      "isRequired": false
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/orders": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "listOrders",
        "summary": "List orders",
        "description": "Lists orders for the branch.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by status.",
            "schema": {
              "$ref": "#/components/schemas/OrderStatus"
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Start of range (Unix ms).",
            "schema": {
              "$ref": "#/components/schemas/UnixMs"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "End of range (Unix ms).",
            "schema": {
              "$ref": "#/components/schemas/UnixMs"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum results.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Pagination offset.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of orders.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderList"
                },
                "example": {
                  "orders": [
                    {
                      "id": 1042,
                      "orderNumber": 88,
                      "type": "delivery",
                      "status": "pending",
                      "paymentStatus": "unpaid",
                      "customerName": "Ahmed Khan",
                      "customerPhone": "03001234567",
                      "subtotal": 1300,
                      "discount": 0,
                      "tax": 0,
                      "total": 1300,
                      "deliveryAddress": "House 5, Block A, Gulshan-e-Iqbal",
                      "notes": "Ring the bell twice",
                      "source": "online",
                      "createdAt": 1728399600000
                    }
                  ],
                  "limit": 10,
                  "offset": 0
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "tags": [
          "Orders"
        ],
        "operationId": "createOrder",
        "summary": "Create an order",
        "description": "Creates a new order. The server looks up item prices from the menu — **you never pass prices**.\n\nThe order immediately appears on the restaurant's POS screen and kitchen display as a new\nonline order. If `online_ordering_enabled` is `\"0\"` in `GET /settings`, this returns `403`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderCreate"
              },
              "example": {
                "type": "delivery",
                "customerName": "Ahmed Khan",
                "customerPhone": "03001234567",
                "deliveryAddress": "House 5, Block A, Gulshan-e-Iqbal",
                "notes": "Ring the bell twice",
                "items": [
                  {
                    "menuItemId": 10,
                    "quantity": 2,
                    "variantId": 6,
                    "notes": "extra spicy",
                    "modifiers": [
                      "Extra Cheese"
                    ]
                  },
                  {
                    "menuItemId": 15,
                    "quantity": 1
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order created.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderCreated"
                },
                "example": {
                  "id": 1042,
                  "orderNumber": 88,
                  "status": "pending",
                  "total": 1750,
                  "createdAt": 1728399600000
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/orders/{id}": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "getOrder",
        "summary": "Get an order",
        "description": "Returns a single order with all its items and modifiers.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                },
                "example": {
                  "id": 1042,
                  "orderNumber": 88,
                  "type": "delivery",
                  "status": "pending",
                  "paymentStatus": "unpaid",
                  "tableNumber": "",
                  "customerName": "Ahmed Khan",
                  "customerPhone": "03001234567",
                  "subtotal": 1300,
                  "discount": 0,
                  "tax": 0,
                  "total": 1300,
                  "deliveryCharge": 150,
                  "tip": 0,
                  "deliveryAddress": "House 5, Block A, Gulshan-e-Iqbal",
                  "notes": "Ring the bell twice",
                  "source": "online",
                  "createdAt": 1728399600000,
                  "items": [
                    {
                      "id": 301,
                      "menuItemId": 10,
                      "menuItemName": "Classic Burger",
                      "variantId": 6,
                      "variantName": "Double",
                      "quantity": 2,
                      "unitPrice": 800,
                      "notes": "extra spicy",
                      "modifiers": [
                        {
                          "name": "Extra Cheese",
                          "extraPrice": 50
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/orders/{id}/status": {
      "patch": {
        "tags": [
          "Orders"
        ],
        "operationId": "updateOrderStatus",
        "summary": "Update order status",
        "description": "Updates the status of an order — useful for delivery apps that mark an order as picked up or delivered.\n\n| Value | Meaning |\n|---|---|\n| `in_progress` | Kitchen is preparing the order |\n| `ready` | Order is ready for pickup or dispatch |\n| `done` | Order completed / delivered |\n| `cancelled` | Order cancelled (stock is automatically restored) |\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderStatusUpdate"
              },
              "example": {
                "status": "done"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status updated.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderStatusResult"
                },
                "example": {
                  "id": 1042,
                  "status": "done"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/customers": {
      "get": {
        "tags": [
          "Customers"
        ],
        "operationId": "listCustomers",
        "summary": "List customers",
        "description": "Lists customers. Supports a partial-match search on name or phone number.",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Partial match on name or phone number.",
            "schema": {
              "type": "string"
            },
            "example": "ahmed"
          }
        ],
        "responses": {
          "200": {
            "description": "Matching customers.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Customer"
                  }
                },
                "example": [
                  {
                    "id": 55,
                    "name": "Ahmed Khan",
                    "phone": "03001234567",
                    "email": "ahmed@example.com",
                    "address": "House 5, Block A",
                    "notes": "Prefers extra spicy",
                    "creditLimit": null,
                    "createdAt": 1720000000000
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "tags": [
          "Customers"
        ],
        "operationId": "createCustomer",
        "summary": "Create a customer",
        "description": "Creates a new customer. The phone number must be unique per restaurant.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerCreate"
              },
              "example": {
                "name": "Ahmed Khan",
                "phone": "03001234567",
                "email": "ahmed@example.com",
                "address": "House 5, Block A, Gulshan-e-Iqbal",
                "notes": "Prefers extra spicy"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created customer.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/customers/{id}": {
      "get": {
        "tags": [
          "Customers"
        ],
        "operationId": "getCustomer",
        "summary": "Get a customer",
        "description": "Returns a single customer.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "The customer.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "patch": {
        "tags": [
          "Customers"
        ],
        "operationId": "updateCustomer",
        "summary": "Update a customer",
        "description": "Updates an existing customer. Send only the fields you want to change.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerUpdate"
              },
              "example": {
                "address": "Flat 3, Defence Housing Authority",
                "notes": "Allergic to peanuts"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated customer.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/branches": {
      "get": {
        "tags": [
          "Branches"
        ],
        "operationId": "listBranches",
        "summary": "List branches",
        "description": "Returns all active branches. Essential for multi-branch restaurants where customers choose a branch before ordering.",
        "responses": {
          "200": {
            "description": "Active branches.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Branch"
                  }
                },
                "example": [
                  {
                    "id": 1,
                    "name": "Main Branch",
                    "address": "Plot 5, Block B, Gulshan-e-Iqbal, Karachi",
                    "phone": "02134567890",
                    "timezone": "Asia/Karachi",
                    "isActive": true,
                    "createdAt": 1720000000000
                  },
                  {
                    "id": 2,
                    "name": "DHA Branch",
                    "address": "6th Commercial, Phase 4, DHA, Karachi",
                    "phone": "02198765432",
                    "timezone": "Asia/Karachi",
                    "isActive": true,
                    "createdAt": 1722000000000
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/discount-codes/apply": {
      "post": {
        "tags": [
          "Discount Codes"
        ],
        "operationId": "applyDiscountCode",
        "summary": "Validate a discount code",
        "description": "Checks whether a code is valid and calculates the discount amount. The usage count only\nincreases when an order is actually placed, so this is safe to call on every keystroke.\n\n`discountAmt = min(subtotal × discountPercent / 100, maxDiscount)`.\nExample: subtotal 1500 with 20% capped at 300 → min(300, 300) = **Rs 300**.\n\nPass the returned `codeId` as `discountCodeId` when creating the order.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DiscountApplyRequest"
              },
              "example": {
                "code": "SUMMER20",
                "subtotal": 1500
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result of the check. `ok: true` with the discount when the code is valid;\n`ok: false` with an `error` message when it is invalid, expired or has reached its limit.\n",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/DiscountApplyValid"
                    },
                    {
                      "$ref": "#/components/schemas/DiscountApplyInvalid"
                    }
                  ]
                },
                "examples": {
                  "valid": {
                    "summary": "Valid code",
                    "value": {
                      "ok": true,
                      "codeId": 12,
                      "discountPercent": 20,
                      "maxDiscount": 300,
                      "discountAmt": 300
                    }
                  },
                  "expired": {
                    "summary": "Expired code",
                    "value": {
                      "ok": false,
                      "error": "Discount code has expired"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/public/{slug}/order/{orderNumber}": {
      "servers": [
        {
          "url": "https://app.mezbanpos.com/api",
          "description": "Public endpoints (no /v1 prefix, no API key)"
        }
      ],
      "get": {
        "tags": [
          "Public Order Tracking"
        ],
        "operationId": "trackOrder",
        "summary": "Track an order (no auth)",
        "description": "Returns live order status by restaurant slug and order number. No API key needed, so you can\nshare a tracking link with the customer after checkout.\n\nYour restaurant's `slug` is shown under **Settings → Account**; it is the unique identifier in\nyour ordering site URL.\n\n| Status | Display to customer |\n|---|---|\n| `pending` | Order received, waiting to be prepared |\n| `in_progress` | Kitchen is preparing your order |\n| `ready` | Your order is ready! |\n| `done` | Order complete / delivered |\n| `cancelled` | Order was cancelled |\n",
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Your restaurant's slug.",
            "schema": {
              "type": "string"
            },
            "example": "my-restaurant"
          },
          {
            "name": "orderNumber",
            "in": "path",
            "required": true,
            "description": "The order number shown to the customer.",
            "schema": {
              "type": "integer"
            },
            "example": 88
          }
        ],
        "responses": {
          "200": {
            "description": "The order's public status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOrder"
                },
                "example": {
                  "orderNumber": 88,
                  "status": "ready",
                  "type": "delivery",
                  "tableNumber": "",
                  "customerName": "Ahmed Khan",
                  "createdAt": 1728399600000,
                  "items": [
                    {
                      "name": "Classic Burger (Double)",
                      "quantity": 2
                    },
                    {
                      "name": "Fries",
                      "quantity": 1
                    }
                  ]
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/settings": {
      "get": {
        "tags": [
          "Settings"
        ],
        "operationId": "getSettings",
        "summary": "Get restaurant settings",
        "description": "Returns all restaurant settings as a flat key–value map of **strings**. The keys relevant for an\nordering integration are documented below; other keys may be present.\n\nIf `online_ordering_enabled` is `\"0\"`, don't show the checkout — `POST /orders` will return `403`.\nCheck this on every page load.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Settings map.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Settings"
                },
                "example": {
                  "online_ordering_enabled": "1",
                  "tax_rate": "13",
                  "currency_symbol": "Rs.",
                  "business_day_start": "06:00",
                  "order_number_mode": "global"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tables": {
      "get": {
        "tags": [
          "Tables"
        ],
        "operationId": "listTables",
        "summary": "List tables",
        "description": "Returns all tables for the branch, including which ones are currently assigned to a server.\n\nFor QR ordering, encode the table number in the QR code URL\n(e.g. `https://yoursite.com/order?table=T3`), read it on page load, and pass it as\n`tableNumber` when creating the order.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Tables.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Table"
                  }
                },
                "example": [
                  {
                    "id": 5,
                    "tableNumber": "T1",
                    "label": "Window Table",
                    "seats": 4,
                    "shape": "round",
                    "floorId": 1,
                    "roomId": 2,
                    "isActive": true,
                    "sortOrder": 0,
                    "assignment_id": null,
                    "server_name": null
                  },
                  {
                    "id": 6,
                    "tableNumber": "T2",
                    "label": "",
                    "seats": 2,
                    "shape": "square",
                    "isActive": true,
                    "sortOrder": 1,
                    "assignment_id": 12,
                    "server_name": "Hamza"
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tables/occupied": {
      "get": {
        "tags": [
          "Tables"
        ],
        "operationId": "listOccupiedTables",
        "summary": "List occupied tables",
        "description": "Returns the table numbers that currently have an open order — useful for showing which tables are taken on a floor plan.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Table numbers with an open order.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "example": [
                  "T2",
                  "T5",
                  "T8"
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/email-receipts/send/{orderId}": {
      "post": {
        "tags": [
          "Email Receipts"
        ],
        "operationId": "sendEmailReceipt",
        "summary": "Email a receipt",
        "description": "Sends a receipt for the given order. Call it right after `POST /orders` succeeds if your checkout collects the customer's email.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "description": "The order ID.",
            "schema": {
              "type": "integer"
            },
            "example": 1042
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailReceiptRequest"
              },
              "example": {
                "email": "ahmed@example.com"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Receipt sent.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                },
                "example": {
                  "ok": true
                }
              }
            }
          },
          "400": {
            "description": "Email receipts are not enabled — configure them in the dashboard first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Email receipts are not enabled"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "description": "The order doesn't exist or belongs to another branch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "Order not found"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/inventory": {
      "get": {
        "tags": [
          "Inventory"
        ],
        "operationId": "listInventoryTransactions",
        "summary": "List stock movements",
        "description": "Returns up to the 200 most recent stock transactions, newest first.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "name": "itemId",
            "in": "query",
            "description": "Filter to a specific menu item.",
            "schema": {
              "type": "integer"
            },
            "example": 10
          }
        ],
        "responses": {
          "200": {
            "description": "Stock transactions.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "maxItems": 200,
                  "items": {
                    "$ref": "#/components/schemas/InventoryTransaction"
                  }
                },
                "example": [
                  {
                    "id": 501,
                    "restaurantId": 1,
                    "branchId": 1,
                    "menuItemId": 10,
                    "changeQty": 50,
                    "reason": "restock",
                    "referenceId": null,
                    "performedBy": 0,
                    "note": "Received from supplier",
                    "createdAt": 1728399600000
                  },
                  {
                    "id": 499,
                    "menuItemId": 10,
                    "changeQty": -2,
                    "reason": "sale",
                    "referenceId": 1042,
                    "note": "",
                    "createdAt": 1728390000000
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "tags": [
          "Inventory"
        ],
        "operationId": "createInventoryTransaction",
        "summary": "Record a stock movement",
        "description": "Logs a stock movement and updates the item's current stock — for example when stock arrives\nfrom a supplier or a count needs correcting.\n\n- **Stock floor:** stock never goes below 0. A deduction that would make it negative sets it to 0.\n- **Low-stock alerts:** if stock falls to or below the item's low-stock threshold, a notification\n  is created in the dashboard.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InventoryCreate"
              },
              "example": {
                "menuItemId": 10,
                "changeQty": 50,
                "reason": "restock",
                "performedBy": 0,
                "note": "Received from Ahsan Traders — invoice #1234"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Movement recorded.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InventoryTransaction"
                },
                "example": {
                  "id": 502,
                  "menuItemId": 10,
                  "changeQty": 50,
                  "reason": "restock",
                  "note": "Received from Ahsan Traders — invoice #1234",
                  "createdAt": 1728399600000
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders": {
      "get": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "listRiders",
        "summary": "List riders",
        "description": "Returns all active riders for the branch.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Active riders.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Rider"
                  }
                },
                "example": [
                  {
                    "id": 8,
                    "name": "Bilal Ahmed",
                    "phone": "03121234567",
                    "type": "freelance",
                    "defaultChargeDisposition": "to_rider",
                    "isActive": true,
                    "createdAt": 1720000000000
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "post": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "createRider",
        "summary": "Add a rider",
        "description": "Registers a new delivery driver. Returns `403` if your plan's rider limit is reached.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RiderCreate"
              },
              "example": {
                "name": "Bilal Ahmed",
                "phone": "03121234567",
                "type": "freelance",
                "defaultChargeDisposition": "to_rider"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created rider.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Rider"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/{id}": {
      "patch": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "updateRider",
        "summary": "Update a rider",
        "description": "Updates a rider's details. Send only the fields to change.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RiderUpdate"
              },
              "example": {
                "phone": "03009876543"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated rider.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Rider"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      },
      "delete": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "deactivateRider",
        "summary": "Deactivate a rider",
        "description": "Deactivates a rider. Returns `400` if the rider has unsettled deliveries — settle them first.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "responses": {
          "200": {
            "description": "Rider deactivated.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OkResponse"
                }
              }
            }
          },
          "400": {
            "description": "The rider has unsettled deliveries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/unassigned-orders": {
      "get": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "listUnassignedOrders",
        "summary": "List unassigned delivery orders",
        "description": "Returns delivery orders that haven't been assigned to a rider yet. Use this to build a dispatch queue.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Unassigned delivery orders.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/UnassignedOrder"
                  }
                },
                "example": [
                  {
                    "id": 1042,
                    "orderNumber": 88,
                    "customerName": "Ahmed Khan",
                    "customerPhone": "03001234567",
                    "deliveryAddress": "House 5, Block A, Gulshan-e-Iqbal",
                    "deliveryCharge": 150,
                    "total": 1750,
                    "paymentMethod": "cash",
                    "status": "ready",
                    "createdAt": 1728399600000
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/assignments": {
      "post": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "createAssignment",
        "summary": "Assign a rider to an order",
        "description": "Assigns a rider to a delivery order. Returns `400` if the order already has an active assignment — cancel that one first.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssignmentCreate"
              },
              "example": {
                "orderId": 1042,
                "riderId": 8,
                "chargeDisposition": "to_rider",
                "paymentMethod": "cod",
                "deliveryCharge": 150,
                "notes": "Call before arriving"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The assignment.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Assignment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/assignments/active": {
      "get": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "listActiveAssignments",
        "summary": "List active assignments",
        "description": "Returns all active (unsettled) assignments across all riders — which rider is on which order right now.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "responses": {
          "200": {
            "description": "Active assignments.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ActiveAssignment"
                  }
                },
                "example": [
                  {
                    "assignment": {
                      "id": 201,
                      "orderId": 1042,
                      "riderId": 8,
                      "status": "picked_up",
                      "chargeDisposition": "to_rider",
                      "deliveryCharge": 150,
                      "paymentMethod": "cod",
                      "codCollected": 0,
                      "assignedAt": 1728399700000,
                      "pickedUpAt": 1728399900000,
                      "deliveredAt": null,
                      "notes": ""
                    },
                    "riderName": "Bilal Ahmed",
                    "riderPhone": "03121234567",
                    "orderNumber": 88,
                    "orderTotal": 1750
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/assignments/by-order/{orderId}": {
      "get": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "getAssignmentByOrder",
        "summary": "Get the assignment for an order",
        "description": "Returns the active rider assignment for an order, or `null` if it isn't assigned yet.",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "description": "The order ID.",
            "schema": {
              "type": "integer"
            },
            "example": 1042
          }
        ],
        "responses": {
          "200": {
            "description": "The active assignment, or `null`.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Assignment"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/assignments/{id}": {
      "patch": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "updateAssignment",
        "summary": "Update an assignment",
        "description": "Moves an assignment through its lifecycle or records cash collected. Send only the fields to change.\n\n```\nassigned → picked_up → delivered\n         ↘ cancelled\n```\n\n| Status | Meaning | Auto-sets |\n|---|---|---|\n| `assigned` | Rider has been dispatched | — |\n| `picked_up` | Rider collected the order | `pickedUpAt` |\n| `delivered` | Order delivered to customer | `deliveredAt` |\n| `cancelled` | Assignment cancelled | — |\n\nWhen the rider delivers and collects cash, send `{\"status\": \"delivered\", \"codCollected\": 1750}`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "$ref": "#/components/parameters/IdPath"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssignmentUpdate"
              },
              "examples": {
                "pickedUp": {
                  "summary": "Rider picked up the order",
                  "value": {
                    "status": "picked_up"
                  }
                },
                "delivered": {
                  "summary": "Delivered, cash collected",
                  "value": {
                    "status": "delivered",
                    "codCollected": 1750
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated assignment.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Assignment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/settlements/{riderId}": {
      "get": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "listSettlements",
        "summary": "List a rider's settlements",
        "description": "Returns settlement history for a rider (up to the 50 most recent).",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          },
          {
            "name": "riderId",
            "in": "path",
            "required": true,
            "description": "The rider ID.",
            "schema": {
              "type": "integer"
            },
            "example": 8
          }
        ],
        "responses": {
          "200": {
            "description": "Settlements, newest first.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "maxItems": 50,
                  "items": {
                    "$ref": "#/components/schemas/Settlement"
                  }
                },
                "example": [
                  {
                    "id": 30,
                    "riderId": 8,
                    "totalOrders": 5,
                    "totalCodCollected": 8500,
                    "chargesToRider": 750,
                    "chargesToRestaurant": 0,
                    "netPayableToRestaurant": 7750,
                    "restaurantOwesRider": 0,
                    "notes": "",
                    "settledAt": 1728400000000
                  }
                ]
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/riders/settlements": {
      "post": {
        "tags": [
          "Delivery Drivers"
        ],
        "operationId": "createSettlement",
        "summary": "Settle a rider's account",
        "description": "Settles all delivered, unsettled assignments for a rider and calculates the cash handover.\nReturns `400` if the rider has nothing to settle.\n\nExample: 5 deliveries, Rs 8,500 cash collected, Rs 750 in delivery fees kept by the rider\n→ the rider hands back 8,500 − 750 = **Rs 7,750**.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/BranchId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SettlementCreate"
              },
              "example": {
                "riderId": 8,
                "notes": "End of shift — 8 Oct 2026"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The settlement.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Settlement"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "webhooks": {
    "orderEvent": {
      "post": {
        "operationId": "orderEventWebhook",
        "summary": "Order event (planned)",
        "description": "**Planned feature — not available yet.** When webhooks ship you'll register a URL in the dashboard\nand receive a `POST` like this whenever one of these events happens:\n\n| Event | Fired when |\n|---|---|\n| `order.created` | A new order is placed |\n| `order.status_changed` | Order status changes (pending → in_progress → ready → done) |\n| `order.cancelled` | An order is cancelled |\n\nUntil then, poll `GET /orders/{id}` every 15–30 seconds until the status is `ready`, `done` or `cancelled`.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              },
              "example": {
                "event": "order.status_changed",
                "restaurantId": 1,
                "data": {
                  "orderId": 1042,
                  "orderNumber": 88,
                  "status": "ready",
                  "previousStatus": "in_progress",
                  "updatedAt": 1728399700000
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge the event."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your API key from **Settings → Integrations → API Key**, sent as `Authorization: Bearer YOUR_API_KEY`."
      }
    },
    "parameters": {
      "BranchId": {
        "name": "X-Branch-Id",
        "in": "header",
        "required": false,
        "description": "Branch to operate on (from `GET /branches`). Defaults to your Main Branch.",
        "schema": {
          "type": "integer"
        },
        "example": 1
      },
      "IdPath": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Resource ID.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Maximum requests per window (120 per minute).",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests remaining in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp when the window resets.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request — invalid or missing fields.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "items must contain between 1 and 50 entries"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Invalid API key"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Subscription expired.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Subscription expired"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Not allowed — for example online ordering is switched off or a plan limit is reached.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Online ordering is disabled"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Item not found"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded (120 requests per minute per API key).",
        "headers": {
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Too many requests"
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Internal server error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Human-readable error message."
          }
        }
      },
      "OkResponse": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "UnixMs": {
        "type": "integer",
        "format": "int64",
        "description": "Unix time in milliseconds.",
        "example": 1728399600000
      },
      "Money": {
        "type": "number",
        "description": "Amount in PKR.",
        "example": 650
      },
      "Category": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 1
          },
          "name": {
            "type": "string",
            "example": "Burgers"
          },
          "color": {
            "type": "string",
            "description": "Hex colour used on the POS., example: '#ef4444'"
          },
          "sortOrder": {
            "type": "integer",
            "example": 0
          },
          "taxRate": {
            "type": [
              "number",
              "null"
            ],
            "description": "Category tax rate in percent; `null` uses the restaurant default."
          }
        }
      },
      "Variant": {
        "type": "object",
        "required": [
          "id",
          "name",
          "priceModifier"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 6
          },
          "name": {
            "type": "string",
            "example": "Double"
          },
          "priceModifier": {
            "$ref": "#/components/schemas/Money",
            "description": "Added to the item's `basePrice`."
          }
        }
      },
      "Modifier": {
        "type": "object",
        "required": [
          "id",
          "name",
          "extraPrice"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 3
          },
          "name": {
            "type": "string",
            "example": "Extra Cheese"
          },
          "extraPrice": {
            "$ref": "#/components/schemas/Money"
          },
          "isRequired": {
            "type": "boolean",
            "example": false
          }
        }
      },
      "MenuItem": {
        "type": "object",
        "required": [
          "id",
          "categoryId",
          "name",
          "basePrice"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 10
          },
          "categoryId": {
            "type": "integer",
            "example": 1
          },
          "name": {
            "type": "string",
            "example": "Classic Burger"
          },
          "description": {
            "type": "string"
          },
          "basePrice": {
            "$ref": "#/components/schemas/Money"
          },
          "imageUrl": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "taxRate": {
            "type": [
              "number",
              "null"
            ],
            "description": "Item tax rate in percent; `null` uses the category or restaurant default."
          },
          "sortOrder": {
            "type": "integer"
          },
          "variants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variant"
            }
          },
          "modifiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Modifier"
            }
          }
        }
      },
      "ComboItem": {
        "type": "object",
        "required": [
          "menuItemId",
          "quantity"
        ],
        "properties": {
          "menuItemId": {
            "type": "integer",
            "example": 10
          },
          "variantId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "quantity": {
            "type": "integer",
            "example": 1
          },
          "allowVariantSelection": {
            "type": "boolean"
          },
          "sortOrder": {
            "type": "integer"
          }
        }
      },
      "Combo": {
        "type": "object",
        "required": [
          "id",
          "name",
          "discountPrice",
          "items"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 2
          },
          "name": {
            "type": "string",
            "example": "Burger Meal"
          },
          "description": {
            "type": "string"
          },
          "discountPrice": {
            "$ref": "#/components/schemas/Money"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ComboItem"
            }
          }
        }
      },
      "Menu": {
        "type": "object",
        "required": [
          "categories",
          "items",
          "combos"
        ],
        "properties": {
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Category"
            }
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MenuItem"
            }
          },
          "combos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Combo"
            }
          }
        }
      },
      "OrderStatus": {
        "type": "string",
        "enum": [
          "pending",
          "in_progress",
          "ready",
          "done",
          "cancelled"
        ]
      },
      "OrderType": {
        "type": "string",
        "enum": [
          "dine_in",
          "takeout",
          "delivery"
        ]
      },
      "OrderSummary": {
        "type": "object",
        "required": [
          "id",
          "orderNumber",
          "type",
          "status",
          "total",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 1042
          },
          "orderNumber": {
            "type": "integer",
            "example": 88
          },
          "type": {
            "$ref": "#/components/schemas/OrderType"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "paymentStatus": {
            "type": "string",
            "example": "unpaid"
          },
          "customerName": {
            "type": "string"
          },
          "customerPhone": {
            "type": "string"
          },
          "subtotal": {
            "$ref": "#/components/schemas/Money"
          },
          "discount": {
            "$ref": "#/components/schemas/Money"
          },
          "tax": {
            "$ref": "#/components/schemas/Money"
          },
          "total": {
            "$ref": "#/components/schemas/Money"
          },
          "deliveryAddress": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "example": "online"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "OrderList": {
        "type": "object",
        "required": [
          "orders",
          "limit",
          "offset"
        ],
        "properties": {
          "orders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderSummary"
            }
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          }
        }
      },
      "OrderItemModifier": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Extra Cheese"
          },
          "extraPrice": {
            "$ref": "#/components/schemas/Money"
          }
        }
      },
      "OrderItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "example": 301
          },
          "menuItemId": {
            "type": "integer",
            "example": 10
          },
          "menuItemName": {
            "type": "string",
            "example": "Classic Burger"
          },
          "variantId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "variantName": {
            "type": [
              "string",
              "null"
            ]
          },
          "quantity": {
            "type": "integer",
            "example": 2
          },
          "unitPrice": {
            "$ref": "#/components/schemas/Money"
          },
          "notes": {
            "type": "string"
          },
          "modifiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrderItemModifier"
            }
          }
        }
      },
      "Order": {
        "allOf": [
          {
            "$ref": "#/components/schemas/OrderSummary"
          },
          {
            "type": "object",
            "properties": {
              "tableNumber": {
                "type": "string"
              },
              "deliveryCharge": {
                "$ref": "#/components/schemas/Money"
              },
              "tip": {
                "$ref": "#/components/schemas/Money"
              },
              "items": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/OrderItem"
                }
              }
            }
          }
        ]
      },
      "OrderCreateItem": {
        "type": "object",
        "required": [
          "menuItemId",
          "quantity"
        ],
        "properties": {
          "menuItemId": {
            "type": "integer",
            "description": "ID from `GET /menu/items`., example: 10"
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100,
            "example": 2
          },
          "variantId": {
            "type": "integer",
            "description": "Variant ID from the item's `variants` list., example: 6"
          },
          "notes": {
            "type": "string",
            "description": "Per-item note for the kitchen., example: extra spicy"
          },
          "modifiers": {
            "type": "array",
            "description": "Modifier **names** from the item's `modifiers` list.",
            "items": {
              "type": "string"
            },
            "example": [
              "Extra Cheese"
            ]
          }
        }
      },
      "OrderCreate": {
        "type": "object",
        "required": [
          "type",
          "items"
        ],
        "properties": {
          "type": {
            "$ref": "#/components/schemas/OrderType"
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/OrderCreateItem"
            }
          },
          "customerName": {
            "type": "string"
          },
          "customerPhone": {
            "type": "string"
          },
          "customerId": {
            "type": "integer",
            "description": "Existing customer ID from `GET /customers`."
          },
          "tableNumber": {
            "type": "string",
            "description": "Table number (for dine-in)."
          },
          "deliveryAddress": {
            "type": "string"
          },
          "notes": {
            "type": "string",
            "description": "Order-level note."
          },
          "discountCodeId": {
            "type": "integer",
            "description": "`codeId` returned by `POST /discount-codes/apply`."
          }
        }
      },
      "OrderCreated": {
        "type": "object",
        "required": [
          "id",
          "orderNumber",
          "status",
          "total",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 1042
          },
          "orderNumber": {
            "type": "integer",
            "example": 88
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "total": {
            "$ref": "#/components/schemas/Money"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "OrderStatusUpdate": {
        "type": "object",
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "in_progress",
              "ready",
              "done",
              "cancelled"
            ]
          }
        }
      },
      "OrderStatusResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          }
        }
      },
      "Customer": {
        "type": "object",
        "required": [
          "id",
          "name",
          "phone"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 55
          },
          "name": {
            "type": "string",
            "example": "Ahmed Khan"
          },
          "phone": {
            "type": "string",
            "example": "03001234567"
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "creditLimit": {
            "type": [
              "number",
              "null"
            ],
            "description": "Credit (udhar) limit in PKR."
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "CustomerCreate": {
        "type": "object",
        "required": [
          "name",
          "phone"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Customer's full name."
          },
          "phone": {
            "type": "string",
            "description": "Phone number (must be unique per restaurant)."
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "address": {
            "type": "string",
            "description": "Default delivery address."
          },
          "notes": {
            "type": "string",
            "description": "Internal notes."
          },
          "creditLimit": {
            "type": "number",
            "description": "Credit (udhar) limit in PKR."
          }
        }
      },
      "CustomerUpdate": {
        "type": "object",
        "description": "Any subset of the customer fields.",
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "address": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          },
          "creditLimit": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "Branch": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 1
          },
          "name": {
            "type": "string",
            "example": "Main Branch"
          },
          "address": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "timezone": {
            "type": "string",
            "example": "Asia/Karachi"
          },
          "isActive": {
            "type": "boolean"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "DiscountApplyRequest": {
        "type": "object",
        "required": [
          "code",
          "subtotal"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Promo code (case-insensitive)., example: SUMMER20"
          },
          "subtotal": {
            "$ref": "#/components/schemas/Money",
            "description": "Cart subtotal in PKR."
          }
        }
      },
      "DiscountApplyValid": {
        "type": "object",
        "required": [
          "ok",
          "codeId",
          "discountAmt"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": true
          },
          "codeId": {
            "type": "integer",
            "description": "Pass as `discountCodeId` when creating the order."
          },
          "discountPercent": {
            "type": "number"
          },
          "maxDiscount": {
            "type": [
              "number",
              "null"
            ],
            "description": "Cap on the discount in PKR."
          },
          "discountAmt": {
            "type": "number",
            "description": "Actual rupee discount: min(subtotal × discountPercent / 100, maxDiscount)."
          }
        }
      },
      "DiscountApplyInvalid": {
        "type": "object",
        "required": [
          "ok",
          "error"
        ],
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string",
            "example": "Discount code has expired"
          }
        }
      },
      "PublicOrder": {
        "type": "object",
        "properties": {
          "orderNumber": {
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "type": {
            "$ref": "#/components/schemas/OrderType"
          },
          "tableNumber": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "example": "Classic Burger (Double)"
                },
                "quantity": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "Settings": {
        "type": "object",
        "description": "Flat map of setting keys to **string** values.",
        "additionalProperties": {
          "type": "string"
        },
        "properties": {
          "online_ordering_enabled": {
            "type": "string",
            "enum": [
              "1",
              "0"
            ],
            "description": "Whether the restaurant is accepting online orders."
          },
          "tax_rate": {
            "type": "string",
            "description": "Default tax rate percentage (numeric string)., example: '13'"
          },
          "currency_symbol": {
            "type": "string",
            "example": "Rs."
          },
          "business_day_start": {
            "type": "string",
            "pattern": "^\\d{2}:\\d{2}$",
            "description": "When the business day starts (for daily order numbering)., example: '06:00'"
          },
          "order_number_mode": {
            "type": "string",
            "example": "global"
          }
        }
      },
      "Table": {
        "type": "object",
        "required": [
          "id",
          "tableNumber"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "tableNumber": {
            "type": "string",
            "example": "T1"
          },
          "label": {
            "type": "string"
          },
          "seats": {
            "type": "integer"
          },
          "shape": {
            "type": "string",
            "example": "round"
          },
          "floorId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "roomId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "isActive": {
            "type": "boolean"
          },
          "sortOrder": {
            "type": "integer"
          },
          "assignment_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Current server assignment, if any."
          },
          "server_name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Name of the assigned server (waiter), if any."
          }
        }
      },
      "EmailReceiptRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          }
        }
      },
      "InventoryReason": {
        "type": "string",
        "enum": [
          "restock",
          "sale",
          "void",
          "refund",
          "adjustment"
        ],
        "description": "- `restock` — stock added (delivery from supplier)\n- `sale` — deducted by a sale\n- `void` — restored by a voided order\n- `refund` — restored by a refund\n- `adjustment` — manual correction\n"
      },
      "InventoryTransaction": {
        "type": "object",
        "required": [
          "id",
          "menuItemId",
          "changeQty",
          "reason",
          "createdAt"
        ],
        "properties": {
          "id": {
            "type": "integer"
          },
          "restaurantId": {
            "type": "integer"
          },
          "branchId": {
            "type": "integer"
          },
          "menuItemId": {
            "type": "integer"
          },
          "changeQty": {
            "type": "integer",
            "description": "Positive adds stock, negative removes it."
          },
          "reason": {
            "$ref": "#/components/schemas/InventoryReason"
          },
          "referenceId": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Related order ID, if any."
          },
          "performedBy": {
            "type": "integer",
            "description": "Staff user ID (0 for API/system)."
          },
          "note": {
            "type": "string"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "InventoryCreate": {
        "type": "object",
        "required": [
          "menuItemId",
          "changeQty",
          "reason",
          "performedBy"
        ],
        "properties": {
          "menuItemId": {
            "type": "integer",
            "description": "The menu item being adjusted."
          },
          "changeQty": {
            "type": "integer",
            "description": "Positive adds stock, negative removes it."
          },
          "reason": {
            "$ref": "#/components/schemas/InventoryReason"
          },
          "performedBy": {
            "type": "integer",
            "description": "Staff user ID; pass `0` for API/system actions."
          },
          "note": {
            "type": "string",
            "description": "Free-text note (e.g. supplier invoice number)."
          },
          "referenceId": {
            "type": "integer",
            "description": "Related order ID if applicable."
          }
        }
      },
      "ChargeDisposition": {
        "type": "string",
        "enum": [
          "to_rider",
          "to_restaurant"
        ],
        "description": "Who gets the delivery charge — `to_rider` (rider keeps the fee) or `to_restaurant`."
      },
      "Rider": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 8
          },
          "name": {
            "type": "string",
            "example": "Bilal Ahmed"
          },
          "phone": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "freelance",
              "employee"
            ]
          },
          "defaultChargeDisposition": {
            "$ref": "#/components/schemas/ChargeDisposition"
          },
          "isActive": {
            "type": "boolean"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "RiderCreate": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Rider's full name."
          },
          "phone": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "freelance",
              "employee"
            ],
            "default": "freelance"
          },
          "defaultChargeDisposition": {
            "$ref": "#/components/schemas/ChargeDisposition"
          }
        }
      },
      "RiderUpdate": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "freelance",
              "employee"
            ]
          },
          "defaultChargeDisposition": {
            "$ref": "#/components/schemas/ChargeDisposition"
          }
        }
      },
      "UnassignedOrder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "orderNumber": {
            "type": "integer"
          },
          "customerName": {
            "type": "string"
          },
          "customerPhone": {
            "type": "string"
          },
          "deliveryAddress": {
            "type": "string"
          },
          "deliveryCharge": {
            "$ref": "#/components/schemas/Money"
          },
          "total": {
            "$ref": "#/components/schemas/Money"
          },
          "paymentMethod": {
            "type": "string",
            "example": "cash"
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "createdAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "AssignmentStatus": {
        "type": "string",
        "enum": [
          "assigned",
          "picked_up",
          "delivered",
          "cancelled"
        ]
      },
      "PaymentMethod": {
        "type": "string",
        "enum": [
          "cod",
          "card",
          "online"
        ]
      },
      "Assignment": {
        "type": "object",
        "required": [
          "id",
          "orderId",
          "riderId",
          "status"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "example": 201
          },
          "orderId": {
            "type": "integer"
          },
          "riderId": {
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/AssignmentStatus"
          },
          "chargeDisposition": {
            "$ref": "#/components/schemas/ChargeDisposition"
          },
          "deliveryCharge": {
            "$ref": "#/components/schemas/Money"
          },
          "paymentMethod": {
            "$ref": "#/components/schemas/PaymentMethod"
          },
          "codCollected": {
            "$ref": "#/components/schemas/Money"
          },
          "assignedAt": {
            "$ref": "#/components/schemas/UnixMs"
          },
          "pickedUpAt": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "deliveredAt": {
            "type": [
              "integer",
              "null"
            ],
            "format": "int64"
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "ActiveAssignment": {
        "type": "object",
        "properties": {
          "assignment": {
            "$ref": "#/components/schemas/Assignment"
          },
          "riderName": {
            "type": "string"
          },
          "riderPhone": {
            "type": "string"
          },
          "orderNumber": {
            "type": "integer"
          },
          "orderTotal": {
            "$ref": "#/components/schemas/Money"
          }
        }
      },
      "AssignmentCreate": {
        "type": "object",
        "required": [
          "orderId",
          "riderId",
          "chargeDisposition"
        ],
        "properties": {
          "orderId": {
            "type": "integer",
            "description": "The delivery order to assign."
          },
          "riderId": {
            "type": "integer",
            "description": "The rider to assign."
          },
          "chargeDisposition": {
            "$ref": "#/components/schemas/ChargeDisposition"
          },
          "paymentMethod": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PaymentMethod"
              }
            ],
            "default": "cod"
          },
          "deliveryCharge": {
            "type": "number",
            "default": 0,
            "description": "Delivery fee in PKR."
          },
          "notes": {
            "type": "string",
            "description": "Instructions for the rider."
          }
        }
      },
      "AssignmentUpdate": {
        "type": "object",
        "minProperties": 1,
        "properties": {
          "status": {
            "$ref": "#/components/schemas/AssignmentStatus"
          },
          "codCollected": {
            "type": "number",
            "description": "Cash collected from the customer, in PKR."
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "Settlement": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "example": 30
          },
          "riderId": {
            "type": "integer"
          },
          "totalOrders": {
            "type": "integer"
          },
          "totalCodCollected": {
            "type": "number",
            "description": "Total cash the rider collected from customers."
          },
          "chargesToRider": {
            "type": "number",
            "description": "Delivery fees the rider keeps (disposition `to_rider`)."
          },
          "chargesToRestaurant": {
            "type": "number",
            "description": "Delivery fees the restaurant covers (disposition `to_restaurant`)."
          },
          "netPayableToRestaurant": {
            "type": "number",
            "description": "Cash the rider hands back: totalCodCollected − chargesToRider."
          },
          "restaurantOwesRider": {
            "type": "number",
            "description": "What the restaurant owes the rider for card/online delivery charges."
          },
          "notes": {
            "type": "string"
          },
          "settledAt": {
            "$ref": "#/components/schemas/UnixMs"
          }
        }
      },
      "SettlementCreate": {
        "type": "object",
        "required": [
          "riderId"
        ],
        "properties": {
          "riderId": {
            "type": "integer"
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "required": [
          "event",
          "restaurantId",
          "data"
        ],
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "order.created",
              "order.status_changed",
              "order.cancelled"
            ]
          },
          "restaurantId": {
            "type": "integer"
          },
          "data": {
            "type": "object",
            "properties": {
              "orderId": {
                "type": "integer"
              },
              "orderNumber": {
                "type": "integer"
              },
              "status": {
                "$ref": "#/components/schemas/OrderStatus"
              },
              "previousStatus": {
                "$ref": "#/components/schemas/OrderStatus"
              },
              "updatedAt": {
                "$ref": "#/components/schemas/UnixMs"
              }
            }
          }
        }
      }
    }
  }
}