{
  "info": {
    "name": "Restora 360 — Public API",
    "description": "Selected public-API endpoints for ordering, reservations, menu, payments, and gift cards on Restora 360-hosted restaurants.\n\nVariables: `{{baseUrl}}` (default `https://restora360.com`), `{{tenantId}}`, `{{orderId}}`, `{{reservationId}}`.\n\nSee https://restora360.com/docs/api/getting-started for auth, rate limits, error envelope, and idempotency conventions.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://restora360.com",
      "type": "string"
    },
    {
      "key": "tenantId",
      "value": "YOUR_TENANT_ID",
      "type": "string"
    },
    {
      "key": "orderId",
      "value": "ord_xxx",
      "type": "string"
    },
    {
      "key": "reservationId",
      "value": "res_xxx",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Bazar auth",
      "description": "Bazar marketplace customer accounts — register, login, current-user lookup, logout. All endpoints issue or read the `bazar_user_session` HttpOnly cookie; no token header.",
      "item": [
        {
          "name": "Register",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/bazar/auth/register",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "bazar",
                "auth",
                "register"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"jane@example.com\",\n  \"password\": \"a-strong-password\",\n  \"name\": \"Jane Doe\",\n  \"gdprConsent\": true\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Creates a new BazarUser account and issues the `bazar_user_session` cookie. Password ≥ 8 chars; GDPR consent must be `true`. 409 when the email is already taken."
          }
        },
        {
          "name": "Login",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/bazar/auth/login",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "bazar",
                "auth",
                "login"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"jane@example.com\",\n  \"password\": \"a-strong-password\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Verifies credentials and issues a fresh session cookie. Rate limit: 8/15 min/IP + 300/15 min global (Phase 67 stacked cap)."
          }
        },
        {
          "name": "Current user",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/bazar/auth/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "bazar",
                "auth",
                "me"
              ]
            },
            "description": "Returns the signed-in user's public profile (id, email, name, preferences, favourites). 401 anon."
          }
        },
        {
          "name": "Logout",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/bazar/auth/logout",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "bazar",
                "auth",
                "logout"
              ]
            },
            "description": "Clears the session cookie. Idempotent — calling without a session still returns 200."
          }
        }
      ]
    },
    {
      "name": "Orders",
      "description": "Public ordering endpoints — submit, retrieve, cancel.",
      "item": [
        {
          "name": "Submit order",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/orders",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "orders"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"delivery\",\n  \"customerName\": \"Jane Doe\",\n  \"customerEmail\": \"jane@example.com\",\n  \"customerPhone\": \"+44 7700 900123\",\n  \"deliveryAddress\": \"12 Example Street\",\n  \"postcode\": \"SW1A 1AA\",\n  \"notes\": \"Doorbell broken — please call on arrival\",\n  \"paymentMethod\": \"cash\",\n  \"items\": [\n    {\n      \"productId\": \"p_abc123\",\n      \"productName\": \"Margherita pizza\",\n      \"quantity\": 1,\n      \"price\": 12.5\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Submits a new order. Server re-validates prices against the menu — do not trust client `price`.\n\nReturns 200 with `{ order }` on success, 4xx with `{ error, message? }` envelope on validation failure, 409 OUTSIDE_RADIUS when the delivery destination is beyond the tenant's `deliveryRadiusKm`.\n\nRate limit: 10 / 10 minutes / IP (per tenant)."
          }
        },
        {
          "name": "Get order",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/orders/{{orderId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "orders",
                "{{orderId}}"
              ]
            },
            "description": "Public-customer order detail. Mirrors the tenant order shape with a few internal fields stripped (escrow IDs, payment intent IDs)."
          }
        },
        {
          "name": "Cancel order",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/orders/{{orderId}}/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "orders",
                "{{orderId}}",
                "cancel"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"Changed my mind\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Customer-initiated cancellation. Refund eligibility depends on the order status at time of request."
          }
        }
      ]
    },
    {
      "name": "Reservations",
      "description": "Public reservation booking and availability.",
      "item": [
        {
          "name": "Get reservation config",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/reservation/config",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "reservation",
                "config"
              ]
            },
            "description": "Returns the tenant's reservation policy: party size range, blocked dates, default slot length. Use this to populate the booking form."
          }
        },
        {
          "name": "Check availability",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/reservation/availability?date=2026-03-15&guestCount=4",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "reservation",
                "availability"
              ],
              "query": [
                {
                  "key": "date",
                  "value": "2026-03-15"
                },
                {
                  "key": "guestCount",
                  "value": "4"
                }
              ]
            },
            "description": "Returns `{ slots: [\"12:00\", \"12:30\", ...] }` for the requested date + party size. Empty array means no availability."
          }
        },
        {
          "name": "Create reservation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/reservation",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "reservation"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"customerName\": \"Jane Doe\",\n  \"customerEmail\": \"jane@example.com\",\n  \"customerPhone\": \"+44 7700 900123\",\n  \"guestCount\": 4,\n  \"date\": \"2026-03-15\",\n  \"timeSlot\": \"19:30\",\n  \"specialRequests\": \"Window table if possible\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Books a reservation. Returns the cancellation token via email so the customer can cancel later.\n\nRate limit: 5 / 10 minutes / IP (per tenant)."
          }
        },
        {
          "name": "Cancel reservation",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/reservation/{{reservationId}}/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "reservation",
                "{{reservationId}}",
                "cancel"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"token\": \"TOKEN_FROM_EMAIL\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Token-gated self-service cancellation. The token is delivered in the booking confirmation email."
          }
        }
      ]
    },
    {
      "name": "Menu",
      "description": "Read-only menu surfaces for storefront and ordering flows.",
      "item": [
        {
          "name": "Get menu filters",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/menu/filters",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "menu",
                "filters"
              ]
            },
            "description": "Returns the tenant's exposed allergen + dietary tag filters for the public menu page. Empty arrays mean the operator hasn't configured filtering."
          }
        }
      ]
    },
    {
      "name": "Payments",
      "description": "Payment intents and coupon validation.",
      "item": [
        {
          "name": "Create payment intent",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/payment-intent",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "payment-intent"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"delivery\",\n  \"customerName\": \"Jane Doe\",\n  \"customerEmail\": \"jane@example.com\",\n  \"customerPhone\": \"+44 7700 900123\",\n  \"items\": [\n    {\n      \"productId\": \"p_abc123\",\n      \"productName\": \"Pizza\",\n      \"quantity\": 1,\n      \"price\": 12.5\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Returns a Stripe PaymentIntent client_secret. Use Stripe Elements on the client to collect card details, then submit the order with the resulting `paymentIntentId`."
          }
        },
        {
          "name": "Validate coupon",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/validate-coupon",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "validate-coupon"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"code\": \"WELCOME10\",\n  \"subtotal\": 25\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Pre-flight coupon check. Returns the resolved discount amount + reason if invalid (expired / min-order / wrong tenant / etc.)."
          }
        }
      ]
    },
    {
      "name": "Gift cards",
      "description": "Gift-card purchase and lookup.",
      "item": [
        {
          "name": "Purchase gift card",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/gift-cards/purchase",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "gift-cards",
                "purchase"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 50,\n  \"recipientName\": \"Jane Doe\",\n  \"recipientEmail\": \"jane@example.com\",\n  \"senderName\": \"John Doe\",\n  \"message\": \"Happy birthday!\",\n  \"deliveryDate\": \"2026-03-15\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Initiates a gift-card purchase. Returns a Stripe client_secret if Stripe is enabled, otherwise a `{ pendingId }` to confirm via the manual flow."
          }
        },
        {
          "name": "Look up gift card",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/public/{{tenantId}}/gift-cards/lookup",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "public",
                "{{tenantId}}",
                "gift-cards",
                "lookup"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"code\": \"K3FX9A2PTMQV\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Returns the remaining balance + expiry for a gift card. Public — anyone with the code can read the balance."
          }
        }
      ]
    }
  ]
}