{"openapi":"3.1.0","info":{"title":"Word of Dish API","version":"1.0.0","description":"Programmatic access to Checks, dishes, and analytics. Authenticate with a Bearer API key (`wod_live_…`) created under **Settings → Integrations**. All requests are scoped to the key's tenant; `read` keys can call GET endpoints, `write` keys can also mint Checks."},"servers":[{"url":"https://wordofdish.com/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Checks","description":"Create and read per-customer Checks."},{"name":"Dishes","description":"Read a store's dish catalog."},{"name":"Analytics","description":"Aggregate feedback analytics."}],"paths":{"/dishes":{"get":{"tags":["Dishes"],"summary":"List a store's dishes","description":"Returns the store's dish catalog. Use the `id`s as `dishId` when minting a Check.","parameters":[{"name":"storeId","in":"query","required":true,"schema":{"type":"string"},"description":"The store to scope the request to."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/DishList"}}}}}},"400":{"description":"storeId missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Store not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/checks":{"get":{"tags":["Checks"],"summary":"List a store's Checks","description":"Newest first, paginated. Pass `?page` (default 1) and `?limit` (default & max 100); the response wraps the `data` array with `page`, `pageSize`, `total`, and `pageCount` so you can walk the rest.","parameters":[{"name":"storeId","in":"query","required":true,"schema":{"type":"string"},"description":"The store to scope the request to."},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"1-based page number."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":100},"description":"Items per page (1–100, default & max 100)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CheckList"},"page":{"type":"integer","description":"1-based page number of this response."},"pageSize":{"type":"integer","description":"Items per page applied (max 100)."},"total":{"type":"integer","description":"Total Checks in the store."},"pageCount":{"type":"integer","description":"Total number of pages."}},"required":["data","page","pageSize","total","pageCount"]}}}},"400":{"description":"storeId missing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Store not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"tags":["Checks"],"summary":"Mint a Check","description":"Creates a per-customer Check and consumes one credit. Returns the diner URL (`url`) to encode as a QR on the customer's receipt. Returns **402** when the tenant is out of credits.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckMintRequest"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/MintedCheck"}}}}}},"400":{"description":"Invalid body or item","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Out of credits (credit gate)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Store not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/checks/{id}":{"get":{"tags":["Checks"],"summary":"Get a Check by id","description":"Includes items, per-dish feedback, and sentiment once the diner has submitted.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CheckDetail"}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Check not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/analytics":{"get":{"tags":["Analytics"],"summary":"Tenant analytics summary","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":365,"default":30},"description":"Look-back window in days."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Analytics"}}}}}},"401":{"description":"Missing or invalid API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"responses":{"RateLimited":{"description":"Too many requests — the per-key rate limit was exceeded. Back off and retry after the window resets.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"wod_live_…","description":"Your API key, e.g. `Authorization: Bearer wod_live_abc123…`."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"},"hint":{"type":"string"}},"required":["error"]},"Dish":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"category":{"type":"string","nullable":true},"price":{"type":"integer","nullable":true,"description":"Minor units (e.g. cents)."},"active":{"type":"boolean"}}},"DishList":{"type":"array","items":{"$ref":"#/components/schemas/Dish"}},"Check":{"type":"object","properties":{"id":{"type":"string"},"shortId":{"type":"string"},"status":{"type":"string","enum":["minted","scanned","submitted"]},"outcome":{"type":"string","nullable":true,"enum":["positive","negative",null]},"url":{"type":"string","format":"uri"},"mintedAt":{"type":"string","format":"date-time","nullable":true},"submittedAt":{"type":"string","format":"date-time","nullable":true}}},"CheckList":{"type":"array","items":{"$ref":"#/components/schemas/Check"}},"MintedCheck":{"type":"object","properties":{"id":{"type":"string"},"shortId":{"type":"string"},"status":{"type":"string"},"url":{"type":"string","format":"uri","description":"Diner survey URL — encode as the Check's QR."}}},"CheckMintRequest":{"type":"object","required":["storeId","items"],"properties":{"storeId":{"type":"string"},"locale":{"type":"string","default":"en","description":"Diner's default locale."},"serverUserId":{"type":"string","description":"Optional staff member to attribute the visit to."},"items":{"type":"array","minItems":1,"items":{"type":"object","required":["dishId"],"properties":{"dishId":{"type":"string","description":"From GET /dishes."},"name":{"type":"string","description":"Human-readable dish label snapshotted onto the Check and shown to the diner (e.g. the `name` from GET /dishes). Strongly recommended: if omitted the Check item is stored without a name."},"qty":{"type":"integer","minimum":1,"default":1},"price":{"type":"integer","description":"Optional per-check price override (minor units)."}}}}}},"CheckDetail":{"type":"object","properties":{"id":{"type":"string"},"shortId":{"type":"string"},"status":{"type":"string"},"outcome":{"type":"string","nullable":true},"items":{"type":"array","items":{"type":"object","properties":{"dishId":{"type":"string","nullable":true},"name":{"type":"string"},"qty":{"type":"integer"},"price":{"type":"integer","nullable":true}}}},"feedback":{"type":"array","items":{"type":"object","properties":{"dishId":{"type":"string","nullable":true},"questionId":{"type":"string","nullable":true},"rating":{"type":"integer","nullable":true},"text":{"type":"string","nullable":true}}}},"sentiment":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"entityId":{"type":"string","nullable":true},"label":{"type":"string","enum":["positive","neutral","negative"]},"score":{"type":"number","nullable":true}}}}}},"Analytics":{"type":"object","properties":{"range":{"type":"object","properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"}}},"reviews":{"type":"integer"},"avgRating":{"type":"number"},"netSentiment":{"type":"number","description":"−1..1 (share positive − share negative)."},"funnel":{"type":"object","additionalProperties":{"type":"number"}},"dishes":{"type":"array","items":{"type":"object","additionalProperties":true}},"staff":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}