{"version":1,"resources":["https://getsauce-kappa.vercel.app/api/orders","https://getsauce-kappa.vercel.app/api/orders/history","https://getsauce-kappa.vercel.app/api/orders/{orderId}"],"description":"Explore 778 New York restaurants on Sauce. Search by delivery address, browse live menus, and get accurate quotes before ordering.","instructions":"# getsauce\n\n778 real New York restaurants that take orders through Sauce (getsauce.com) — from Di Fara\nPizza to a hundred bagel shops — indexed so an agent can find the ones that will actually\ndeliver to a given address, and quote the real total before ordering.\n\n## Start with the address\n\nDelivery is geofenced, not radial. 710 of the 856 zones in this catalog are polygons; a store\nhalf a mile away may still refuse your block. So the first call is always the address:\n\n    GET /api/restaurants?address=277 Bedford Ave, Brooklyn, NY 11211\n\nThat filters 778 storefronts down to the ones whose delivery zone actually contains the\ndestination, sorted nearest first. Pass `lat` and `lng` instead if you already have\ncoordinates — it skips geocoding and is faster.\n\n## Quote before you commit\n\nAdd the planned subtotal and the response tells you what the order really costs:\n\n    GET /api/restaurants?address=...&subtotal=35\n\nEach result then carries `fees` (resolved from fixed or percentage), `zone.minSubtotal`,\n`belowMinimum` and `smallOrderFee`. This matters: across the catalog a $35 order carries a median 33% markup\nonce fees, tax and the default tip land, and the 90th-percentile fee is five times the median.\nDo not assume a typical fee — read the store's.\n\n## Looking for a dish, not a restaurant?\n\nDo not fetch menus one by one. 95k items are indexed across every store:\n\n    GET /api/items?address=...&q=chicken shawarma\n\nOne call returns matching items with the restaurant, distance, ETA and fees attached, filtered\nto stores that deliver to the address. Add `format=wrap` (derived: wrap, bowl, platter, slice,\npita, hero, ...), `maxPrice`, or `sort=price`.\n\n`price` is the EFFECTIVE minimum — base plus the cheapest mandatory choices. Sauce\nstub-prices some items (a $1.00 base with a required $18.20 size), so `basePrice` on its own\nis not what anyone pays. Sort and filter on `price`; `stubBasePrice: true` marks the items\nwhere the two diverge.\n\n## Is it open?\n\nEvery result carries `openNow`, computed from the store's posted schedule in its own\ntimezone — not guessed. Filter with:\n\n    GET /api/restaurants?address=...&openNow=true\n\n`null` means the store publishes no hours: unknown, not closed, so those are kept. Results\nalso carry `localTime`, `closesAt` and `opensAt` as local wall clock (\"Mon 21:45\").\n\nOne honest limit: this is the *posted schedule*. A store can be inside its hours and still\nhave paused ordering. That flag is live state we refuse to bake, so ask for it explicitly:\n\n    GET /api/restaurants/{slug}?live=true\n\nThat returns `temporarilyPaused` (the raw manual pause bit — note a store closed until\nWednesday is NOT paused, it is merely shut) and `orderableNow`, which is the composite you\nactually want: open per schedule AND not paused. Both are null when anything is unknown.\n\n## Getting a real total\n\nDo not assemble it yourself — the inputs live in three different documents upstream:\n\n    GET /api/quote?slug=zaab-zaab-williamsburg&subtotal=47&address=277 Bedford Ave, Brooklyn, NY 11211\n\nReturns subtotal, every applicable fee, tax, tip presets, and the total, with a `checksum`\nyou can verify. Two bases are called out explicitly and they are not equally certain:\n`tax.baseVerified` is true (subtotal only — confirmed against a live order), while\n`tip.baseVerified` is false (we compute on subtotal, but Sauce has not confirmed it — worth\nabout a dollar on a $50 order). Works for pickup too, with no address.\n\n## Endpoints (reads are free and unauthenticated; ordering is paid)\n\n    POST /api/orders                      paid order — verified DID or payer wallet must be allowlisted\n    GET  /api/orders/history              your past orders + recentDestinations (SIWX)\n    GET  /api/orders/{id}                 retrieve one of your orders (SIWX)\n    GET /api/quote                        full priced total for an order — use this, do not add up fees by hand\n    GET /api/items                        cross-restaurant item search — start here for a dish\n    GET /api/restaurants                  search by address; see query params above\n    GET /api/restaurants/{slug}           full detail: fees, tips, zones, POS\n    GET /api/restaurants/{slug}/menu      menu, slim by default with modifier choices resolved\n                                          inline. view=full for raw Sauce; q= / section= to filter\n    GET /api/boroughs                     borough list with counts\n\n## Ordering and payment\n\nOrdering is live and paid over x402 (and MPP where your wallet supports it). The flow:\n\n1. Find a store and confirm it is open: `/api/restaurants?address=...&openNow=true`\n2. Pick items: `/api/restaurants/{slug}/menu` — note any group with `required: true`\n3. Check the total you are about to be charged: `/api/quote?slug=...&subtotal=...&address=...`\n4. Place it:\n\n    POST /api/orders\n    {\n      \"slug\": \"12-chairs-cafe\",\n      \"items\": [{\"itemId\": \"<id from the menu>\", \"quantity\": 1}],\n      \"fulfillment\": \"delivery\",\n      \"address\": \"277 Bedford Ave, Brooklyn, NY 11211\",\n      \"customer\": {\"name\": \"...\", \"phone\": \"+1...\"},\n      \"clientRequestId\": \"<generate a fresh UUID>\"\n    }\n\nThe 402 challenge is the real order total for exactly those items — the same arithmetic\n`/api/quote` returns, so you can verify the amount before paying. Settle it and the response\nis your confirmed order with an id and an ETA. No API key is required. Follow the\n`X-Agent-Identity` challenge on the 402; AgentCash does this automatically. The verified DID,\nor the verified payer wallet when no DID is supplied, must have an enabled `OrderAccessGrant`.\nA denied identity receives 403 and its payment is not settled. Retrieve the order later with\n`GET /api/orders/{id}`.\n\nGenerate a fresh UUID for `clientRequestId` for every new order and keep it with your trace.\nReusing a completed UUID returns 409 before a payment challenge. If a response was lost, do not\nretry the paid request with a new UUID: call `GET /api/orders/history` and match the original\n`clientRequestId`. This prevents a retry from paying again or returning a different order.\n\nTwo things to get right before you pay:\n\n- **Check `openNow`.** Orders to a closed store are rejected with a 409.\n- **Resolve required choices.** 89% of menus have at least one mandatory modifier group. Omit\n  them and you are charged the cheapest legal option rather than what you meant to order.\n\n## \"Send it to my usual address\"\n\nWhen the human says *the usual*, *same as last time*, *my address*, *last address*, or gives you\na name and phone but no street — do NOT ask them to retype it. Look it up:\n\n    GET /api/orders/history        (SIWX, free)\n\n`recentDestinations` comes back newest-first, each entry an address + phone + name pair with\nhow many times it has been used. `recentDestinations[0]` IS the last address. Take the\n`address` and `phone` straight from it and put them in your next `POST /api/orders`.\n\n    recentDestinations: [\n      { address: \"277 Bedford Ave, Brooklyn, NY 11211\", phone: \"+1...\", name: \"...\",\n        lastUsedAt: \"2026-08-03T18:45:25Z\", orderCount: 4 }\n    ]\n\nRules of thumb:\n\n- Empty `recentDestinations` means this identity has never ordered. Only then ask the human.\n- `address: null` was a pickup order — do not use it as a delivery address.\n- More than one entry? Prefer the most recent, but say which you picked. If they asked for\n  \"home\" or \"the office\" and you have several, ask rather than guess — a misdelivered order\n  cannot be cancelled.\n- The address still has to be in range for the restaurant you chose. Re-check it against\n  `/api/restaurants?address=...`; a past address is not automatically deliverable today.\n\nHistory is scoped to customer identity, not necessarily the payment account. When the client\nsends a verified `X-Agent-Identity` proof, its DID owns the order; otherwise the verified wallet\nis the compatibility identifier. The response records `payer` separately, so delegated wallets\nand SPT-backed payment can change without changing who can retrieve the order. You can only see\nyour own orders, and `GET /api/orders/{id}` uses the same identity boundary.\n\nThere is no cancel or refund endpoint. That is not an omission on our side — Sauce's own\nstorefront API has none either. An order placed cannot be taken back in code.\n\n## Things worth knowing\n\n- 138 storefronts share a kitchen with another brand — 386 Canal St runs four. They have\n  separate ids, menus and payouts, so they are separate entries here, not duplicates.\n- 89% of menus contain at least one required modifier group. You cannot add most items to a\n  cart without resolving a mandatory choice first. The slim menu view resolves the choices\n  inline — Sauce itself returns modifier groups with an empty options array and hides the real\n  choices in the top-level items array.\n- 305 stores enforce a minimum tip. Sending zero is not always allowed.\n- `zone.minSubtotal` is NOT a blocker. Below it, Sauce still accepts the order and charges a\n  small-order fee instead — `belowMinimum` plus `smallOrderFee` tell you the real cost. Do not\n  reject a restaurant for being under its minimum.\n- Tax applies to the item subtotal only. Fees and tips are not taxed.\n- Hours are real data, not inference: overnight windows are explicit (Sun 11:30 -> Mon 03:45)\n  and daylight saving is handled by comparing wall clock in the store's IANA zone.\n- Prices are decimal USD, matching Sauce. Convert to minor units at your own boundary.\n"}