Home Setup

Setup

By Hamad
• 28 articles

Connect your own system: orders API and webhooks

For: Owners, Operations Where: Setup > Integrations > Webhooks, API keys Available: Web dashboard · All countries This guide is for the developer who connects a restaurant's own system to Zyda, such as an ERP, a POS or a spreadsheet tool. It covers both directions: Zyda sending orders to your system, and your system sending orders to Zyda. How it works - Webhooks (Zyda to your system). Zyda sends you an HTTP request when one of the store's orders changes. - Orders API (your system to Zyda). You send Zyda the orders the store took outside Zyda, for example on a marketplace or on the phone. You can use one direction, or both. Someone at the store who can open Setup > Integrations sets up both in the dashboard. See Set up webhooks and API keys. All examples on this page are made up. They contain no real key, secret, store or customer. The API keys page, with the address your system sends orders to Zyda's webhooks, which send your orders to your system as they happen, have their own guide: Receive Zyda orders by webhook. Get an API key 1. In the Zyda dashboard, open Setup > Integrations > API keys. 2. Select Create key, then Create. 3. Copy the key. Zyda shows it once. Keep it on your server only. A key starts with zyda_sk_. The key names the store, so you never send a store id. The store can revoke a key at any time. A store can have up to 10 active keys. Send an order POST https://dashboard.zyda.com/api/v1/stores/orders Authorization: Bearer <key> Content-Type: application/json - Send one order per request, as a JSON object. - The body can be at most 256 KB. - One key can make at most 120 requests a minute. Over that, the answer is 429 with a Retry-After header in seconds. What Zyda does with the order depends on status: - completed or canceled: a recorded sale. Zyda stores the sale. Nothing else happens: no message to the customer, no kitchen ticket, no POS push, no webhook event. - placed: a live order. The order is still open. It goes to the store's current orders, and staff move it through its statuses. This works only for an order source with Show in current orders turned on. See "Live orders". Order fields Fields marked required must be present and not blank. Zyda ignores fields that are not listed here. | Field | Type | Required | Notes | |---|---|---|---| | branch_id | integer | required | Zyda's id of the branch. It must be a branch of the store that owns the key. | | channel | string | required | The order source. One of the keys in "Order sources" below. The store must have it turned on. | | external_order_id | string | required | Your own id for the order. At most 128 characters. Letter case is ignored, so ERP-1 and erp-1 are the same order. | | placed_at | string | required | When the customer placed the order. ISO 8601 with a time zone, for example 2026-10-14T13:05:00+03:00. At most 10 minutes in the future. | | status | string | required | completed, canceled or placed. | | total | number | required | What the customer paid in total. See "Money". | | currency | string | required | The store's currency code, for example KWD or EGP. Any other currency is refused. | | subtotal | number | optional | See "Money". | | discount | number | optional | See "Money". | | delivery_fee | number | optional | See "Money". | | tax | number | optional | See "Money". | | delivery_type | string | optional | delivery, pickup or dine_in. | | payment_method | string | optional | cash, card_on_delivery or prepaid. | | notes | string | optional | Free text. At most 2000 characters. On a live order, staff see the first 1000 characters as the order note. The customer never sees it. | | customer | object | optional | See "The customer object". null is accepted. | | items | array | optional | The order lines. At most 200. See "The item object". | The customer object | Field | Type | Required | Notes | |---|---|---|---| | name | string | optional | At most 255 characters. | | phone | string | optional | At most 32 characters. Required for a live order. | Zyda finds the customer by phone only. A local number is read in the store's country, or send the country code (+965...). An invalid phone links no customer, but a recorded sale is still saved. The item object Each line in items: | Field | Type | Required | Notes | |---|---|---|---| | name | string | required | At most 255 characters. | | quantity | number | required | More than 0 and less than 100,000. Zyda keeps 3 decimals, so 1.5 kg is 1.5. Must be a whole number on a live order. | | unit_price | number | required | The price of one unit. See "Money". | | external_item_id | string | optional | Your own id for the product. At most 128 characters. | | zyda_item_id | integer | optional | Zyda's id of the product variant. At most 2,147,483,647. Required on every line of a live order. | | modifiers | array | optional | Options on the line. At most 50. See "The modifier object". | The modifier object Each entry in modifiers: | Field | Type | Required | Notes | |---|---|---|---| | name | string | required | At most 255 characters. | | quantity | number | optional | Left out, null or blank means 1. | | unit_price | number | optional | Left out, null or blank means 0. | | external_id | string | optional | Your own id for the option. At most 128 characters. | Order sources The value of channel is one of these keys: website, app, whatsapp, instagram, facebook, tiktok, phone, walk_in, talabat, instashop, deliveroo, keeta, jahez, hungerstation, careem, noon_food, elmenus, breadfast, snoonu, mrsool, the_chefz, rafeeq, other The store turns sources on and off in Setup > Business > Order sources. A source that is turned off is refused for a new order. A resend or a cancel of an order Zyda already holds is still accepted after the store turns its source off. Money Every amount is in the store's currency, from 0 up to less than 1,000,000,000, with 3 decimals kept. Send a JSON number or a string of digits. A string such as "12.750" avoids rounding errors. Send the same order again channel plus external_order_id names one order of the store. Sending it again never makes a second order. So it is safe to retry a request after a timeout. Sending a recorded sale again updates it (200, "result": "updated"). Required fields are replaced. An optional field you leave out keeps its old value. items, when sent, replaces all lines. To cancel it, send it again with "status": "canceled". It cannot be sent again as placed. If two requests for the same order arrive at the same time, one of them gets 409. Send it again after a few seconds. Live orders An order with "status": "placed" becomes a live order when its source has Show in current orders turned on (Setup > Business > Order sources). It reaches the store's current orders like an order a staff member keys in. On any other source, placed is refused with 422. Send the order once it is completed instead. A live order sent with the API: - sends the customer no message; - pays no Zyda order commission; - earns the customer no loyalty points or cashback; - sends no purchase event to the store's ad platforms; - still goes to the store's POS, alerts the staff and is accepted automatically if the store accepts orders automatically. Version 1 limits. Zyda refuses each one with 422 and its own message: - delivery_type must be pickup, or left out. Version 1 takes no delivery address. - items is required. - Every line needs zyda_item_id, the Zyda id of the product variant. - The product must be published at the branch and allow pickup. It must not be a combo, and it must not need options chosen. - Every line's quantity is a whole number. The whole order holds at most 9,999 units. - customer.phone is required and must be a valid phone number. - payment_method is cash, card_on_delivery or prepaid. Left out, it is cash. prepaid means the money is already taken. Zyda takes no payment. Zyda's menu prices the order, and the answer carries Zyda's total. Staff see modifiers as text on the line. The store can still refuse the order, for example when the branch is closed or an item is out of stock. The answer is then 422. The reason is in errors.order, and its code is in code. No order is made. After the order is placed, staff move it in Zyda. Follow its status with webhooks. To cancel it, send it again with "status": "canceled" (200, "result": "canceled"; Zyda never refunds; 409 if the store can no longer cancel it). Any other resend changes nothing (200, "result": "unchanged"). Answers Every answer is JSON. A success answer holds Zyda's id, the result, your channel and external_order_id, and the order's status in Zyda. kind is imported_order for a recorded sale and order for a live order. customer_linked is true when Zyda found or made the customer from the phone. A live order also has order_number and Zyda's total. | Code | Meaning | |---|---| | 201 | The order is new and Zyda saved it. "result": "created". | | 200 | Zyda already had this order. updated: a recorded sale took the new values. unchanged: a live order sent again stays as it is. canceled: you canceled a live order. | | 400 | The body is not a JSON object. | | 401 | The key is missing, unknown or revoked. | | 409 | Another request is writing the same order right now, or the store can no longer cancel this live order. | | 413 | The body is larger than 256 KB. | | 422 | A field is missing or wrong, or the store refused a live order (see errors.order). | | 429 | More than 120 requests in a minute for this key. Wait the seconds in Retry-After. | | 503 | Zyda cannot take the order right now. Send it again later. | Every error answer has an error message. A 422 also has errors. It maps each field name to one or more messages. Line fields are named by position, for example items[2].quantity: { "error": "invalid order", "errors": { "placed_at": ["is required"], "items[0].quantity": ["must be greater than 0"] } } Retry 409, 429, 503 and network errors with the same body. Do not retry 400, 401, 413 or 422 until you change the request. Example: a recorded sale Request body: { "branch_id": 101, "channel": "instashop", "external_order_id": "ERP-100045", "placed_at": "2026-10-14T13:05:00+03:00", "status": "completed", "total": "12.750", "currency": "KWD", "delivery_fee": "0.750", "delivery_type": "delivery", "payment_method": "prepaid", "customer": { "name": "Sample Customer", "phone": "+96550000000" }, "items": [ { "name": "Ribeye steak", "quantity": "1.5", "unit_price": "8.000", "external_item_id": "SKU-RIB", "modifiers": [{ "name": "Sliced thin", "external_id": "MOD-SLICE" }] } ] } Answer 201: { "id": 5012, "result": "created", "kind": "imported_order", "channel": "instashop", "external_order_id": "ERP-100045", "status": "completed", "customer_linked": true } Example: a live order Request (the source whatsapp has Show in current orders turned on): { "branch_id": 101, "channel": "whatsapp", "external_order_id": "ERP-100046", "placed_at": "2026-10-14T13:20:00+03:00", "status": "placed", "total": "9.500", "currency": "KWD", "delivery_type": "pickup", "payment_method": "cash", "customer": { "name": "Sample Customer", "phone": "+96550000000" }, "items": [ { "name": "Burger patties, 6 pieces", "quantity": 2, "unit_price": "4.750", "zyda_item_id": 123456, "modifiers": [{ "name": "Extra fat" }] } ] } Answer 201: { "id": 880123, "result": "created", "kind": "order", "order_number": "1042", "channel": "whatsapp", "external_order_id": "ERP-100046", "status": "submitted", "customer_linked": true, "total": 9.5 } Rules and limits - Up to 5 webhooks and up to 10 active API keys per store. - 120 requests a minute per key. Bodies up to 256 KB. Up to 200 lines per order and 50 modifiers per line. - The delivery log keeps 30 days. Common questions Does Zyda message the customer about an order I send? No. Neither a recorded sale nor a live order sends the customer anything. Can a live order be a delivery order? Not in version 1. A live order must be pickup. Send a delivery order once it is completed, as a recorded sale. My webhook stopped. Why? After 50 failed deliveries in a row, Zyda turns it off. Fix your endpoint, then turn Send events back on. The delivery log shows each error. Related articles - Set up webhooks and API keys - Choose the order sources your team records - Send your orders to a Google Sheet

Last updated on Oct 20, 2026

Integrate with Foodics

Connect your Zyda store to Foodics so you do not enter the same data in two systems. Owners and managers can do this. Foodics is a point of sale and order management platform for restaurants, retail stores, caterers, chefs and others in the food industry. The integration synchronises Foodics with your Zyda store, which removes manual data entry and cuts your costs. Before you start - The integration costs $8 each month, paid in your store's local currency. The fee goes directly to Foodics. - Every branch you have in Foodics must have a matching branch in Zyda. - Importing the menu from Foodics removes and replaces your old menu in Zyda. Steps In Zyda 1. Turn taxes off. Go to Setup, select Business Information, scroll down and turn off Licensed Business. 2. Turn card on delivery off. Go to Setup, select Payment Gateways, scroll down and turn off Card on Delivery. 3. Turn auto accept off. Go to Setup, select Orders Management, scroll down, turn off Auto Accept Orders, then click Save Changes. 4. Connect Foodics. Go to Setup, select Integrations, click Get Started, read the instructions, then click Connect Now. Now sign in to your Foodics dashboard with your credentials and set up the charges, the taxes and the menu. In Foodics 1. Create the delivery charge. Go to Manage, click More, select Charges, then Create Charge. Set Name to delivery from zyda, written exactly like that. Set Type to Amount. Set Value to Yes, so the cashier can type the charge value by hand. Set Apply to Delivery. Pick the branches and the tax you want. Click Save. 2. Check your taxes. Go to Manage, click Taxes & Groups, and make sure your tax settings hold the tax details you need. 3. Create a menu group for Zyda. Go to Menu, click Groups, create a group and give it a name. Select the products or the categories you want to import. Click Save. Import your menu into Zyda 1. Go to Menu and select Items. 2. At the top right, click the options icon and select Import catalog from foodics. 3. Match each Foodics branch to its branch in Zyda, then click Next. 4. Under Menu Groups, select the group you created in Foodics. 5. Click Save. You receive an email listing every product that was not imported, and what to fix so it imports successfully. Make every later menu change in Foodics. The change then reaches Zyda. The import takes a couple of minutes, and up to 24 hours for a large menu. Watch a short video of this

Last updated on Sep 17, 2026