{
  "openapi": "3.1.1",
  "jsonSchemaDialect": "https://json-schema.org/draft/2020-12/schema",
  "info": {
    "title": "Blizzfull API",
    "version": "2.4.0",
    "summary": "Read a restaurant's menu, keep it in sync, and put orders into its kitchen.",
    "description": "The Blizzfull API connects point-of-sale systems, ordering partners and AI agents to Blizzfull restaurants.\n\n## Getting access\nEvery request sends an API user and token. A key belongs to one restaurant (or to a partner's restaurants) and can be narrowed to the calls it needs. Ask your Blizzfull contact for a key; you get a sandbox key first.\n\n## Conventions\n- **Base URL:** `https://apiv2.blizzfull.com`.\n- **Envelope:** a successful response is `{\"response\": ...}`.\n- **Errors:** a refusal is the HTTP status with `{\"response\": \"<what to fix>\"}`. A failure inside the order or menu engine is HTTP 400 with `{\"type\": \"exception\", \"message\": ..., \"code\": ...}`.\n- **Money:** orders (StandardOrder) use integer cents. Menus use dollars: numbers when you send them, decimal strings in the feed.\n- **Time:** ISO 8601, UTC.\n- **IDs:** Blizzfull's IDs. A menu import uses your own IDs, and Blizzfull remembers the mapping.\n- **Rate limits:** 1,200 requests a minute per key, 300 of them writes, and 30 order or menu creations every 5 minutes. Over the limit you get HTTP 429 with `Retry-After`.\n- **Compatibility:** fields are added without notice; ignore the ones you don't use.\n\n## Machine-readable\nThis document and its schemas are served from `https://apiv2.blizzfull.com/schema/`: `openapi.json`, `standard-order.schema.json`, `menu-feed.schema.json` and `blizzfullMenuSchema.json` (JSON Schema 2020-12).",
    "contact": {
      "name": "Blizzfull developer support",
      "url": "https://blizzfull.com/developer"
    }
  },
  "servers": [
    {
      "url": "https://apiv2.blizzfull.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiUser": [],
      "ApiToken": []
    }
  ],
  "tags": [
    {
      "name": "Menu",
      "description": "Read a restaurant's live menu, or send yours to Blizzfull."
    },
    {
      "name": "Orders",
      "description": "Place orders into a restaurant and read them back as StandardOrder."
    },
    {
      "name": "Point of sale",
      "description": "For point-of-sale partners: pick up new orders and confirm them."
    }
  ],
  "paths": {
    "/items/getFullMenu": {
      "get": {
        "operationId": "getMenuFeed",
        "tags": [
          "Menu"
        ],
        "summary": "Get the live menu",
        "description": "The restaurant's whole menu as customers see it now: categories, items, sizes, option groups and options, with what is sold out. Everything you need to build an order is here: an item's `id`, its sizes' `id`, and each option group's `linkageID` with its options' `id`.\n\nRead it at the start of a session and again when an order is refused for an unknown item; it can be large (a few MB for a big menu).",
        "parameters": [
          {
            "name": "restaurantID",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Your key's restaurant."
          },
          {
            "name": "locationID",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                1
              ]
            },
            "description": "Always 1."
          }
        ],
        "responses": {
          "200": {
            "description": "The menu.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "response"
                  ],
                  "properties": {
                    "response": {
                      "$ref": "#/components/schemas/MenuFeed"
                    }
                  }
                },
                "example": {
                  "response": [
                    {
                      "id": "26900",
                      "name": "Combos",
                      "shortName": "combos",
                      "description": "",
                      "parent": "0",
                      "position": "0",
                      "specialType": null,
                      "active": true,
                      "displayOnly": false,
                      "secret": false,
                      "isMenu": false,
                      "availableTimeData": null,
                      "availableFrom": null,
                      "availableUntil": null,
                      "media": null,
                      "children": null,
                      "items": [
                        {
                          "id": 166519,
                          "name": "Hungry Combo",
                          "description": "Tenders or wings, a flavor, a side and a drink.",
                          "category": "26900",
                          "categoryName": "Combos",
                          "categoryShortName": "combos",
                          "price": "16.50",
                          "inactive": false,
                          "inactiveEnds": null,
                          "sizeable": false,
                          "sizes": null,
                          "media": null,
                          "spicy": false,
                          "vegetarian": false,
                          "gf": false,
                          "keto": false,
                          "alcoholic": false,
                          "taxExempt": false,
                          "orderTypeRestriction": "",
                          "options": [],
                          "fooditems": [
                            {
                              "id": 221801,
                              "name": "Hungry Combo",
                              "description": "",
                              "options": [
                                {
                                  "linkageID": "216385",
                                  "id": "97001",
                                  "componentID": "221801",
                                  "title": "Choose a style",
                                  "phrase": "",
                                  "kitchenname": "",
                                  "type": "TYPE_SINGLE_SELECT",
                                  "required": true,
                                  "position": "1",
                                  "defaultIndex": 0,
                                  "extraProps": null,
                                  "sizeEffects": null,
                                  "items": [
                                    {
                                      "id": "441415",
                                      "name": "6 Tenders",
                                      "cost": 0,
                                      "default": 0,
                                      "unavailableUntil": "0",
                                      "position": 1,
                                      "media": null,
                                      "subOptions": null
                                    },
                                    {
                                      "id": "441416",
                                      "name": "8 Wings",
                                      "cost": 0,
                                      "default": 0,
                                      "unavailableUntil": "0",
                                      "position": 2,
                                      "media": null,
                                      "subOptions": null
                                    }
                                  ]
                                },
                                {
                                  "linkageID": "216386",
                                  "id": "97002",
                                  "componentID": "221801",
                                  "title": "Choose a flavor",
                                  "phrase": "",
                                  "kitchenname": "",
                                  "type": "TYPE_SINGLE_SELECT",
                                  "required": true,
                                  "position": "2",
                                  "defaultIndex": 0,
                                  "extraProps": null,
                                  "sizeEffects": null,
                                  "items": [
                                    {
                                      "id": "441417",
                                      "name": "Lemon Pepper",
                                      "cost": 0,
                                      "default": 0,
                                      "unavailableUntil": "0",
                                      "position": 1,
                                      "media": null,
                                      "subOptions": null
                                    },
                                    {
                                      "id": "441418",
                                      "name": "Mango Habanero",
                                      "cost": 0.5,
                                      "default": 0,
                                      "unavailableUntil": "0",
                                      "position": 2,
                                      "media": null,
                                      "subOptions": null
                                    }
                                  ]
                                }
                              ]
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/menu/import": {
      "post": {
        "operationId": "importMenu",
        "tags": [
          "Menu"
        ],
        "summary": "Import a menu",
        "description": "Creates or updates the restaurant's menu from your menu, keyed by your IDs: importing the same IDs again updates the same records.\n\nThis call does not check the menu against the schema first, and a menu missing a required field can stop part-way. Validate against `blizzfullMenuSchema.json` before you send. A menu sent without any earlier sync replaces the restaurant's menu.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuImport"
              },
              "example": {
                "categories": [
                  {
                    "id": "wings",
                    "name": "Wings",
                    "items": [
                      {
                        "id": "w6",
                        "name": "6 Wings",
                        "price": 9.99,
                        "tags": [
                          "spicy"
                        ],
                        "groups": [
                          {
                            "id": "flavors",
                            "required": true
                          }
                        ]
                      }
                    ]
                  }
                ],
                "option_groups": [
                  {
                    "id": "flavors",
                    "name": "Flavor",
                    "type": "TYPE_SINGLE_SELECT",
                    "options": [
                      {
                        "id": "buffalo",
                        "name": "Buffalo",
                        "price": 0
                      },
                      {
                        "id": "lemon-pepper",
                        "name": "Lemon Pepper",
                        "price": 0.5
                      }
                    ]
                  }
                ],
                "sizes": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Imported.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "string",
                      "enum": [
                        "success"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/menu/importExternalPOSMenu/{posName}": {
      "post": {
        "operationId": "importPointOfSaleMenu",
        "tags": [
          "Menu",
          "Point of sale"
        ],
        "summary": "Send your point of sale's menu",
        "description": "For a point-of-sale partner installed at the restaurant. Checks the menu against the schema, then stores it so the restaurant can map its Blizzfull menu to your items. When the restaurant has made your system its menu's source of truth, the menu is also imported into the live menu.",
        "parameters": [
          {
            "name": "posName",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your integration's name at Blizzfull.",
            "example": "4soft"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MenuImport"
              },
              "example": {
                "categories": [
                  {
                    "id": "wings",
                    "name": "Wings",
                    "items": [
                      {
                        "id": "w6",
                        "name": "6 Wings",
                        "price": 9.99,
                        "tags": [
                          "spicy"
                        ],
                        "groups": [
                          {
                            "id": "flavors",
                            "required": true
                          }
                        ]
                      }
                    ]
                  }
                ],
                "option_groups": [
                  {
                    "id": "flavors",
                    "name": "Flavor",
                    "type": "TYPE_SINGLE_SELECT",
                    "options": [
                      {
                        "id": "buffalo",
                        "name": "Buffalo",
                        "price": 0
                      },
                      {
                        "id": "lemon-pepper",
                        "name": "Lemon Pepper",
                        "price": 0.5
                      }
                    ]
                  }
                ],
                "sizes": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stored (and imported, when your system is the menu's source of truth).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "description": "Refused: the JSON is malformed or doesn't match the schema (`errors` lists each problem), the integration is missing or disabled, or `enforceSyncCompatibility` doesn't match.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/orders": {
      "post": {
        "operationId": "createOrder",
        "tags": [
          "Orders"
        ],
        "summary": "Place an order",
        "description": "Places a pickup order at your key's restaurant, exactly as you send it: your lines, choices and prices are the order. Blizzfull adds tax, submits it to the restaurant like any online order (their tablet, printers and point of sale take it from there), and returns it as a StandardOrder with the order number and total.\n\nThe customer pays at pickup. The order shows in the restaurant's reports as a phone order.\n\n**Retries are safe:** send a `tempID`. If a request times out, send the same body again; an order already placed with that `tempID` in the last 24 hours comes back (HTTP 200) instead of a second one being made.\n\n**Building lines:** take each item's `id`, size `id` and choices from the menu feed. `totalPrice` is the line's total in cents (item, size and options, times quantity) and becomes the line's price. Every line needs its `name` and `totalPrice`, so an item the menu no longer has is still recorded as the caller ordered it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrderRequest"
              },
              "example": {
                "tempID": "kp1001",
                "type": "PICKUP",
                "isFuture": true,
                "fulfillmentTime": "2026-10-28T19:30:00-07:00",
                "customer": {
                  "name": "Dana Rivera",
                  "phone": "(661) 555-0177"
                },
                "note": "Called in by phone",
                "items": [
                  {
                    "id": {
                      "internal": 166519
                    },
                    "name": "Hungry Combo",
                    "quantity": 1,
                    "totalPrice": 1650,
                    "optionSelections": [
                      {
                        "optionGroupId": "216385",
                        "selections": [
                          {
                            "optionItemId": "441415",
                            "selected": 1
                          }
                        ]
                      },
                      {
                        "optionGroupId": "216386",
                        "selections": [
                          {
                            "optionItemId": "441417",
                            "selected": 1
                          }
                        ]
                      }
                    ],
                    "note": "Sauce on the side"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Placed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                },
                "example": {
                  "response": {
                    "order": {
                      "id": {
                        "internal": "2303306",
                        "external": null
                      },
                      "status": "SUBMITTED",
                      "type": "PICKUP",
                      "sourcePlatform": "phone",
                      "isFuture": true,
                      "pickupTime": "2026-10-29T02:30:00+00:00",
                      "fulfillmentTime": "2026-10-29T02:30:00+00:00",
                      "taxRate": "8.2500",
                      "processingVia": "manual",
                      "merchant": {
                        "name": "Example Wings",
                        "id": {
                          "internal": "1234",
                          "external": null
                        },
                        "timezone": "America/Los_Angeles"
                      },
                      "customer": {
                        "id": "776304",
                        "name": "Dana Rivera",
                        "phone": "+16615550177",
                        "phoneExt": ""
                      },
                      "items": [
                        {
                          "quantity": 1,
                          "orderItemID": 1,
                          "id": {
                            "internal": 166519,
                            "external": null
                          },
                          "name": "Hungry Combo",
                          "note": "Sauce on the side",
                          "unitPrice": 1650,
                          "totalPrice": 1650,
                          "taxRate": 8.25,
                          "optionSelections": [
                            {
                              "optionGroupId": "216385",
                              "selections": [
                                {
                                  "optionItemId": "441415",
                                  "selected": 1
                                }
                              ]
                            },
                            {
                              "optionGroupId": "216386",
                              "selections": [
                                {
                                  "optionItemId": "441417",
                                  "selected": 1
                                }
                              ]
                            }
                          ]
                        }
                      ],
                      "totals": {
                        "subtotal": 1650,
                        "tip": 0,
                        "extraCharge": 0,
                        "deliveryFee": 0,
                        "tax": 136,
                        "dspWithheldTax": 0,
                        "total": 1786,
                        "discount": 0,
                        "paid": 0,
                        "balanceOwed": 1786
                      },
                      "transactions": []
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "A retry with a `tempID` already used: the order the first request placed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrderResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EngineError"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/orders/{orderId}/getWithRestaurantStd": {
      "get": {
        "operationId": "getOrder",
        "tags": [
          "Orders"
        ],
        "summary": "Get an order",
        "description": "One order as a StandardOrder, with the restaurant details a receipt needs. Use it to check an order's status (`SUBMITTED`, `ACCEPTED`, `FULFILLED`, `CANCELED`) and ready time.",
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^(ex-)?[1-9][0-9]*$"
            },
            "description": "The order number (`id.internal`), or `ex-<n>` for a marketplace order."
          }
        ],
        "responses": {
          "200": {
            "description": "The order.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "response"
                  ],
                  "properties": {
                    "response": {
                      "type": "object",
                      "properties": {
                        "order": {
                          "$ref": "#/components/schemas/StandardOrder"
                        },
                        "restaurant": {
                          "type": "object",
                          "description": "The restaurant's name, address, time zone and receipt settings.",
                          "properties": {
                            "restaurantID": {
                              "type": "string",
                              "description": "The Blizzfull restaurant ID."
                            },
                            "name": {
                              "type": "string",
                              "description": "The restaurant's name."
                            },
                            "streetAddress": {
                              "type": "string",
                              "description": "Street address."
                            },
                            "city": {
                              "type": "string",
                              "description": "City."
                            },
                            "state": {
                              "type": "string",
                              "description": "Two-letter state code."
                            },
                            "zip": {
                              "type": "string",
                              "description": "ZIP code."
                            },
                            "timeZone": {
                              "type": "string",
                              "description": "IANA time zone, for showing the order's times locally."
                            },
                            "websiteURL": {
                              "type": "string",
                              "description": "The restaurant's website."
                            }
                          }
                        },
                        "receiptLocale": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "additionalReceiptLocale": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/orders/poll": {
      "get": {
        "operationId": "pollOrders",
        "tags": [
          "Point of sale"
        ],
        "summary": "Pick up new orders",
        "description": "Orders submitted (or accepted) since a time you give, for a point of sale to take into its own ticket flow. Poll every few seconds with the time of the newest order you have.\n\nOrders come in Blizzfull's internal order format; with `posToMap`, each is transformed into your integration's ticket format.",
        "parameters": [
          {
            "name": "orderList",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]+(,[01])?$"
            },
            "description": "`<unix seconds>,<0|1>`: orders submitted after that time, or with `,1`, orders accepted after it.",
            "example": "1793142409,0"
          },
          {
            "name": "posToMap",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Your integration's name: returns each order in your ticket format, using the restaurant's item mapping."
          },
          {
            "name": "receiveExternalOrders",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "1 also returns marketplace orders Blizzfull relays. Requires `posToMap`."
          },
          {
            "name": "returnRaw",
            "in": "query",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "1 returns the order list itself, without the `response.orderList.data` wrapping."
          }
        ],
        "responses": {
          "200": {
            "description": "The new orders; `orderList` is absent when there are none.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "object",
                      "properties": {
                        "orderList": {
                          "type": "object",
                          "properties": {
                            "data": {
                              "type": "array",
                              "items": {
                                "type": "object",
                                "description": "An order in Blizzfull's internal format, or your ticket format with `posToMap`."
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "`posToMap` names an integration the restaurant doesn't have.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/Refused"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/orders/{orderId}/accept": {
      "post": {
        "operationId": "acceptOrder",
        "tags": [
          "Point of sale"
        ],
        "summary": "Accept an order",
        "description": "Confirms an order on the restaurant's behalf with a ready time. The customer is told it was accepted, and a delivery order's courier is booked.",
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^(ex-)?[1-9][0-9]*$"
            },
            "description": "The order number (`id.internal`), or `ex-<n>` for a marketplace order."
          }
        ],
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "readyTime": {
                    "type": "integer",
                    "description": "Minutes until the order is ready. 0 uses the restaurant's default."
                  },
                  "eta": {
                    "type": "string",
                    "description": "When a delivery courier should pick up, ISO 8601 UTC."
                  },
                  "busyMode": {
                    "type": "integer",
                    "enum": [
                      -1,
                      0,
                      1
                    ],
                    "description": "1 turns the restaurant's busy mode on, -1 turns it off, 0 (or left out) leaves it as it is."
                  },
                  "bypassDelayedTime": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "description": "1 starts a scheduled order now instead of at its scheduled time."
                  },
                  "bypassCourier": {
                    "type": "integer",
                    "enum": [
                      0,
                      1
                    ],
                    "description": "1 accepts a delivery order without booking a courier."
                  }
                }
              },
              "example": {
                "readyTime": 20
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "response": {
                      "type": "object",
                      "properties": {
                        "accepted": {
                          "type": "integer",
                          "enum": [
                            1
                          ]
                        },
                        "estimatedReadyTime": {
                          "type": [
                            "integer",
                            "string"
                          ],
                          "description": "Unix seconds."
                        },
                        "readyTimeInputValue": {
                          "type": [
                            "integer",
                            "string"
                          ]
                        },
                        "pickupETA": {
                          "type": [
                            "integer",
                            "boolean"
                          ]
                        },
                        "lastModified": {
                          "type": [
                            "integer",
                            "string"
                          ]
                        },
                        "delivery": {
                          "type": "object",
                          "description": "The booked delivery, for delivery orders."
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiUser": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Blizzfull-API-User",
        "description": "Your API user name."
      },
      "ApiToken": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Blizzfull-API-Token",
        "description": "Your API token. Keep it secret; it is shown once."
      }
    },
    "schemas": {
      "StandardOrder": {
        "$ref": "standard-order.schema.json"
      },
      "MenuFeed": {
        "$ref": "menu-feed.schema.json"
      },
      "MenuImport": {
        "$ref": "blizzfullMenuSchema.json"
      },
      "OrderResponse": {
        "type": "object",
        "required": [
          "response"
        ],
        "properties": {
          "response": {
            "type": "object",
            "required": [
              "order"
            ],
            "properties": {
              "order": {
                "$ref": "#/components/schemas/StandardOrder"
              }
            }
          }
        }
      },
      "CreateOrderRequest": {
        "type": "object",
        "description": "A pickup order, in StandardOrder's shape. Only these fields are read.",
        "required": [
          "type",
          "customer",
          "items"
        ],
        "properties": {
          "tempID": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{1,8}$",
            "description": "Your reference for this order, 1 to 8 letters, digits, `-` or `_`, unique per order. Makes retries safe."
          },
          "type": {
            "type": "string",
            "enum": [
              "PICKUP"
            ]
          },
          "isFuture": {
            "type": "boolean",
            "description": "True for an order scheduled for `fulfillmentTime`. Leave out for as soon as possible."
          },
          "fulfillmentTime": {
            "type": "string",
            "format": "date-time",
            "description": "When the customer will pick up, with an offset. Read only when `isFuture` is true."
          },
          "delayedTime": {
            "type": "integer",
            "description": "Alternative to `isFuture` + `fulfillmentTime`: the pickup time in Unix seconds. 0 means as soon as possible."
          },
          "customer": {
            "type": "object",
            "required": [
              "phone"
            ],
            "properties": {
              "name": {
                "type": "string",
                "description": "Called out at pickup. Split into first and last name at the first space."
              },
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              },
              "phone": {
                "type": "string",
                "description": "The callback number; at least 10 digits, any formatting.",
                "examples": [
                  "(661) 555-0177"
                ]
              },
              "phoneExt": {
                "type": "string"
              },
              "email": {
                "type": "string",
                "format": "email",
                "description": "Optional. When given, the order joins the customer's Blizzfull account for that email; otherwise the account for the phone number."
              }
            }
          },
          "note": {
            "type": "string",
            "description": "Instructions for the whole order."
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "required": [
                "id",
                "name",
                "totalPrice"
              ],
              "properties": {
                "id": {
                  "type": "object",
                  "required": [
                    "internal"
                  ],
                  "properties": {
                    "internal": {
                      "type": "integer",
                      "description": "The item's `id` from the menu feed."
                    }
                  }
                },
                "name": {
                  "type": "string",
                  "description": "The item's name, as the caller ordered it."
                },
                "quantity": {
                  "type": "integer",
                  "minimum": 1,
                  "default": 1
                },
                "totalPrice": {
                  "type": "integer",
                  "exclusiveMinimum": 0,
                  "description": "The line total in cents: item, size and options, times quantity."
                },
                "size": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "object",
                      "properties": {
                        "internal": {
                          "type": [
                            "string",
                            "integer"
                          ],
                          "description": "The size's `id` from the menu feed."
                        }
                      }
                    }
                  }
                },
                "optionSelections": {
                  "type": "array",
                  "description": "The caller's choices. List what differs from the menu's defaults.",
                  "items": {
                    "$ref": "standard-order.schema.json#/$defs/OptionGroupSelection"
                  }
                },
                "note": {
                  "type": "string",
                  "description": "Instructions for this line."
                }
              }
            }
          },
          "discounts": {
            "type": "array",
            "description": "Order-level discounts. Their amounts are added up and taken off the order (never below zero); names are not kept.",
            "items": {
              "type": "object",
              "required": [
                "amount"
              ],
              "properties": {
                "amount": {
                  "type": "integer",
                  "description": "Cents."
                }
              }
            }
          }
        }
      },
      "Message": {
        "type": "object",
        "required": [
          "response"
        ],
        "properties": {
          "response": {
            "type": "string",
            "description": "What happened, or what to fix."
          }
        }
      },
      "EngineErrorBody": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "exception"
            ]
          },
          "message": {
            "type": "string"
          },
          "code": {
            "type": "integer"
          },
          "trace": {
            "type": "null"
          },
          "request": {
            "type": "string"
          }
        }
      },
      "ImportError": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "error"
            ]
          },
          "message": {
            "type": "string"
          },
          "code": {
            "type": "integer"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "property": {
                  "type": "string",
                  "description": "Where, as a path (`option_groups[0].name`)."
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "responses": {
      "Refused": {
        "description": "Refused: the message names the field to fix.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Message"
            },
            "example": {
              "response": "items[0].totalPrice must be the line total in cents"
            }
          }
        }
      },
      "EngineError": {
        "description": "The order engine couldn't take the order, for example a choice that isn't on the item.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/EngineErrorBody"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The API user or token is missing or wrong.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Message"
            },
            "example": {
              "response": "Unauthorized"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key may not make this call, or not for this restaurant or order.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Message"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Over the rate limit. Wait `Retry-After` seconds.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "Seconds to wait."
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Message"
            }
          }
        }
      }
    }
  }
}
