- Added optional
itemDiscountsin the Item object under Order relay to carry item-level discounts - Added optional
discountAmountin the Variants object under Order relay - For items with
itemDiscounts,unitPrice(item and variants) andsubTotalare now the listed prices before the discount, andorderInfo.subTotalis the sum of those listed subtotals - Clarified that item-level discounts are not sent in
orderInfo.discounts
Connect your POS to Ownly.
Push your menu, receive orders and keep order status in sync. The guides explain what each integration does; the API reference gives every contract.
Build the integration in this order.
- Authenticate your requests.Authentication
- Push your menu and handle the processing callback.Menu push
- Expose the order endpoint and receive orders.Order relay
- Send accepted, cancelled and food ready; receive customer cancellations.Order status exchange
- Expose the rider status endpoint and, if you need to call customers or riders, use call masking.Rider status
- Keep stock and store availability current.Inventory update
Follow one order through both systems.
How an order moves between Ownly and your downstream system, from the new order to delivery.
These calls cover the whole integration.
Authentication.
Downstream systems authenticate with Basic Auth. Each contract also lists the request header it expects.
Key header
Auth key
Authorization header; every other call documents the key header. Keep both server-side and never ship them in a client app or a repository.Which header each call uses
| Endpoint | Header | Called by |
|---|---|---|
POST /api/v1/menu | key | Your POS |
POST /api/v1/item-status | Authorization | Your POS |
POST /api/v1/store-status | key | Your POS |
POST /api/v1/order-status | key | Both |
GET /api/v1/contact | key, plus Accept: application/json | Your POS |
POST /api/v1/order/ | key | Ownly |
POST <upstream-host>/api/v1/rider-status | key | Ownly |
How the integration works.
The document is a reference for downstream systems integrating with Ownly for menu, order, order status exchange, item inventory and restaurant status.
Order relay
Every time a customer places an order, Ownly relays the order details to your system.
Order status exchange
Once an order is placed it goes through a life cycle, and both systems exchange its status.
Your system pushes order acceptance, order rejection and food ready to Ownly. Ownly pushes the customer cancellation and the rider updates, from assignment to delivery, to your system.
Ownly exposes
An endpoint to receive acceptance, cancellation and food ready from your system.
Item inventory
Update the stock status of an item, add-on or variant. Your system calls Ownly with the stock details.
Restaurant status
Switch a store on or off. Use it to take a restaurant offline when the kitchen is closed or overwhelmed.
Call masking
Retrieve a masked contact number and an OTP to start a call between two parties on an order, for example from the restaurant to the customer.
Order life cycle
The calls an order passes through, in order. The last two rows are alternatives that can end an order early.
| Step | Sent from and to | Call and value |
|---|---|---|
| Order placed | Ownly→Your POS | POST /api/v1/order/Sends status: placed |
| Order accepted | Your POS→Ownly | POST /api/v1/order-statusSends RESTAURANT_ACCEPTED |
| Food ready | Your POS→Ownly | POST /api/v1/order-statusSends FOOD_READY |
| Rider assigned | Ownly→Your POS | POST <upstream-host>/api/v1/rider-statusSends RIDER_ASSIGNED |
| Rider at store | Ownly→Your POS | POST <upstream-host>/api/v1/rider-statusSends RIDER_AT_STORE |
| Out for delivery | Ownly→Your POS | POST <upstream-host>/api/v1/rider-statusSends OUT_FOR_DELIVERY |
| Reached drop location | Ownly→Your POS | POST <upstream-host>/api/v1/rider-statusSends REACHED_DROP_LOCATION |
| Delivered | Ownly→Your POS | POST <upstream-host>/api/v1/rider-statusSends DELIVERED |
| Restaurant cancels Alternative | Your POS→Ownly | POST /api/v1/order-statusSends RESTAURANT_CANCELLED |
| Customer cancels Alternative | Ownly→Your POS | POST /api/v1/order-statusSends CUSTOMER_CANCELLED |
Ready to build? Open the API reference.
API reference.
The Ownly API is organised around REST. Every call, grouped by what it manages.
Conventions
Request and response bodies in the samples are JSON. Examples that name a host use https://api.baseurl.com as a placeholder; replace it with the base URL for your integration. Rider status is the exception: it lives on your own host, shown as <upstream-host>.
Success
200A JSON body with a message.
Failure
400A JSON body with an error message. The field is error or message as each contract shows.
Auth
The key header on most calls, Authorization on inventory. See Authentication.
Endpoints by group
Menu management
POST/api/v1/menuPush the full menuOwnlyPOST/api/v1/item-statusUpdate stock for items, variants and add-onsOwnlyOrder management
POST/api/v1/order/Receive a new order from OwnlyYour POSPOST/api/v1/order-statusExchange accepted, ready and cancelledBothGET/api/v1/contactGet a masked number and OTP for a callOwnlyRider management
POST<upstream-host>/api/v1/rider-statusReceive rider assignment through deliveryYour POSStore management
POST/api/v1/store-statusTurn ordering on or off for a storeOwnlyInventory update.
Update the stock status of items, variants and add-ons in Ownly. Use it to mark things out of stock, and to say when they return.
inStock value to every item, variant and add-on you list.Request headers
| Header | Description |
|---|---|
Authorization | Basic Auth |
Request body
| Parameter | Type | Description | Required |
|---|---|---|---|
restId | string | The unique identifier for the restaurant. | Required |
items | string[] | Menu item identifiers whose stock status is changing. | Required |
variants | string[] | Variant identifiers whose stock status needs an update. | Required |
addOns | string[] | Add-on identifiers whose stock status needs an update. | Required |
inStock | boolean | The availability status. true means available, false means out of stock. Applies to all specified items, variants and add-ons. | Required |
nextAvailableAt | integer | Unix timestamp in milliseconds (13 digits) for when the out-of-stock items will be restocked. Note: We kindly recommend managing stock restoration directly from your side. | Optional |
Sample request
POST /api/v1/item-status Authorization: Basic <credentials> { "restId": "53349", "addOns": [ "1595275" ], "inStock": false, "items": [ "701172" ], "variants": [ "1595518" ], "nextAvailableAt": 1717209600000 }
Responses
{
"message": "Item Inventory updated successfully"
}{
"error": "error message"
}Order relay.
Ownly relays every new order to your system. Expose this endpoint and Ownly will call it each time a customer places an order.
Request headers
| Header | Description |
|---|---|
key | Key |
Request body
| Parameter | Type | Description | Required |
|---|---|---|---|
orderInfo | Order info object | The key details about the order itself: order id, restaurant id, order type, discounts, and charges like subtotal, taxes and total. It also carries payment mode, preparation time and delivery mode. | Required |
payment | Payment object | The payment details: the method (for example cash, card or UPI), the status (paid or unpaid) and the amounts. | Required |
customer | Customer object | Details about the customer placing the order: first name, last name and an optional masked phone number. | Required |
items | Item object[] | The individual menu items in the order, including item id, name, quantity, price and associated charges or instructions. | Required |
otp | OTP object | One-time passwords for pickup and drop verification. | Optional |
prepTimeDetails | Prep time details object | Predicted kitchen preparation time and the allowed adjustment thresholds. Omitted when not provided. | Optional |
Objects
Order info
| Parameter | Type | Description | Required |
|---|---|---|---|
orderId | string | The unique identifier for the order. | Required |
restId | string | The unique identifier for the restaurant. | Required |
instruction | string | Special instructions from the customer, for example "Please make it extra spicy". | Optional |
status | string | The current status of the order. Always placed here. | Required |
subTotal | float | The total price of the items excluding taxes and charges. When items have itemDiscounts, it is the total at listed prices, before item discounts. | Required |
totalPackingCharge | float | Total charge for packing collected. | Optional |
totalTaxes | float | The total tax amount. | Required |
createdAt | int | The Unix timestamp when the order was placed. | Required |
total | float | The total amount: total = subtotal + charges + taxes. | Required |
deliveryMode | string | The mode of delivery. One of self_delivery, delivery. | Optional |
discounts | Discount object[] | Order-level discounts applied to the order. Omitted when none exist. | Optional |
Discount
| Parameter | Type | Description | Required |
|---|---|---|---|
scope | string | Where the discount applies. CART applies to the entire cart and order total. ITEM is reserved: item-level discounts are not sent here, they are sent in items[].itemDiscounts. | Required |
value | float | The discount value. Its meaning depends on type. | Required |
type | string | How value is read. PERCENTAGE: value is the percentage (10 means 10% off). FIXED: value is the amount in currency units (50.9 means ₹50.90 off). | Required |
Payment
| Parameter | Type | Description | Required |
|---|---|---|---|
mode | string | The mode of payment used. For example, "online". | Required |
status | string | The current payment status. Possible value: paid. | Required |
amountPaid | float | The amount paid by the customer. For example, 500.00 rupees. | Required |
Customer
| Parameter | Type | Description | Required |
|---|---|---|---|
firstName | string | The customer's first name. For example, "John". | Required |
lastName | string | The customer's last name. For example, "Doe". | Required |
phoneNumber | string | Customer phone, as a masked number (partially redacted for privacy). | Optional |
OTP
| Parameter | Type | Description | Required |
|---|---|---|---|
pickup | integer | OTP for pickup verification. | Optional |
drop | integer | OTP for drop-off verification. | Optional |
Prep time details
| Parameter | Type | Description | Required |
|---|---|---|---|
predictedPrepTime | integer | Initial kitchen preparation time in minutes. For example, 15. | Optional |
maxIncreaseThreshold | integer | Maximum minutes the restaurant may increase predictedPrepTime. Allowed maximum is predictedPrepTime + maxIncreaseThreshold (15 + 3 = 18). | Optional |
maxDecreaseThreshold | integer | Maximum minutes the restaurant may decrease predictedPrepTime. Allowed minimum is predictedPrepTime − maxDecreaseThreshold (15 − 5 = 10). | Optional |
If prepTimeDetails is omitted, continue with the existing preparation time workflow.
Item
| Parameter | Type | Description | Required |
|---|---|---|---|
itemId | string | The unique identifier for the item. | Required |
name | string | The name of the item. For example, "Chicken Biryani". | Required |
quantity | integer | The quantity of the item. For example, 2. | Required |
unitPrice | float | The price per unit, for example 250.00 rupees. This is the listed price, before any discount. When the item has itemDiscounts, the discount is not applied to unitPrice; it is given separately in itemDiscounts. | Required |
taxes | Taxes object[] | The tax details for the item. | Required |
charges | Charges object[] | Additional charges applicable for the item. | Required |
instruction | string | Special instructions for the item. For example, "Extra Spicy". | Optional |
variants | Variants object[] | The variant details for the item, for example size or type. | Conditional |
addOns | Add-on object[] | Add-ons associated with the item. | Conditional |
itemDiscounts | Item discount object[] | Discounts applied to this item and its variants. Omitted when the item has no discount. At most one entry per item. Not repeated in orderInfo.discounts. | Optional |
Item discount
| Parameter | Type | Description | Required |
|---|---|---|---|
id | string | The unique identifier of the offer that produced the discount. | Required |
title | string | The display name of the offer. For example, "First Off". | Required |
mode | string | How the offer is configured: PERCENTAGE or FIXED. Informational only; use amount for the discount value. | Required |
value | float | The configured discount: a percentage when mode is PERCENTAGE (20 means 20% off), or an amount in currency units when FIXED. Informational only. | Required |
amount | float | Total discount for the whole line, in currency units: the item plus all its discounted variants, multiplied by quantity. Equals itemAmount + variantAmount. This is the amount to subtract from the item subTotal. | Required |
itemAmount | float | The part of amount that comes from the base item, multiplied by quantity. | Required |
variantAmount | float | The part of amount that comes from the item's variants, including nested variants, multiplied by quantity. 0 when no variant is discounted. | Required |
- For an item with
itemDiscounts,unitPrice(item and variants) and the itemsubTotalare the listed prices before the discount. The amount charged for the line issubTotal − amount. - The item total is
subTotal − amount + item taxes. Taxes are calculated on the discounted amount. orderInfo.subTotalis the sum of the itemsubTotalvalues, before item discounts.orderInfo.totalis the amount payable:total = subTotal − item discounts − order-level (CART) discounts + taxes + charges.- Discounted variants carry their own
discountAmount. Add-ons are not discounted. - Item-level discounts are never aggregated into
orderInfo.discounts, which only carries order-level (CART) discounts. - Items without a discount are unchanged: no
itemDiscounts, and the prices are the charged prices.
Variants
| Parameter | Type | Description | Required |
|---|---|---|---|
id | string | The unique identifier for the variant. | Required |
name | string | The name of the variant. For example, "Large". | Optional |
unitPrice | float | The price of the variant, for example 100.00 rupees. This is the listed price, before any discount. | Required |
discountAmount | float | The discount on this variant for the whole line: the per-unit discount × item quantity. Present only when the variant is discounted. The sum over all variants equals variantAmount in the Item discount object. | Optional |
variants | Variants object[] | Nested variant details. | Conditional |
addOns | Add-on object[] | Additional add-ons associated with the variant. | Conditional |
Add-on
| Parameter | Type | Description | Required |
|---|---|---|---|
id | string | The unique identifier for the add-on. | Required |
name | string | The name of the add-on. For example, "Extra Cheese". | Required |
unitPrice | float | The price of the add-on. For example, 50.00 rupees. | Required |
Taxes
| Parameter | Type | Description | Required |
|---|---|---|---|
title | string | The name of the tax. For example, "SGST". | Required |
value | float | The tax amount. For example, 25.00 rupees. | Required |
percentage | float | The tax percentage. For example, 2.50. | Required |
liabilityOn | string | restaurant or aggregator. | Required |
Charges
| Parameter | Type | Description | Required |
|---|---|---|---|
title | string | The name of the charge. For example, "Delivery Charge". | Required |
value | float | The amount of the charge. For example, 30.00 rupees. | Required |
liability_on | string | restaurant or aggregator. | Required |
Sample request
POST /api/v1/order/ key: <key> { "orderInfo": { "orderId": "ORD123456", "restId": "REST1001", "instruction": "Make it spicy", "status": "placed", "subTotal": 500.0, "totalPackingCharge": 20.0, "totalTaxes": 45.0, "createdAt": 1717046400, "total": 565.0, "deliveryMode": "delivery", "discounts": [ { "scope": "CART", "value": 10, "type": "PERCENTAGE" } ] }, "payment": { "mode": "online", "status": "paid", "amountPaid": 565.0 }, "customer": { "firstName": "John", "lastName": "Doe", "phoneNumber": "98******10" }, "otp": { "pickup": 1234, "drop": 1244 }, "prepTimeDetails": { "predictedPrepTime": 15, "maxIncreaseThreshold": 3, "maxDecreaseThreshold": 5 }, "items": [ { "itemId": "ITEM001", "name": "Chicken Biryani", "quantity": 2, "unitPrice": 312.5, "instruction": "Extra Spicy", "itemDiscounts": [ { "id": "OFFER001", "title": "First Off", "mode": "PERCENTAGE", "value": 20, "amount": 175.0, "itemAmount": 125.0, "variantAmount": 50.0 } ], "taxes": [ { "title": "SGST", "value": 12.5, "percentage": 2.5, "liability_on": "restaurant" }, { "title": "CGST", "value": 12.5, "percentage": 2.5, "liability_on": "restaurant" } ], "charges": [ { "title": "Packing Charge", "value": 10.0, "liability_on": "restaurant" } ], "variants": [ { "id": "VAR001", "name": "Family Pack", "unitPrice": 125.0, "discountAmount": 50.0, "variants": [], "addOns": [ { "id": "ADDON001", "name": "Extra Raita", "unitPrice": 20.0 } ] } ], "addOns": [ { "id": "ADDON002", "name": "Extra Salad", "unitPrice": 15.0 } ] } ] }
Responses
{
"message": "Order Details successfully communicated."
}{
"error": "error message"
}Order status exchange.
Both systems expose this endpoint to exchange an order's status. Your POS sends acceptance, cancellation and food ready; Ownly sends customer cancellation.
Request headers
| Header | Description |
|---|---|
key | Key |
Request body
| Parameter | Type | Description | Required |
|---|---|---|---|
orderId | string | The Ownly order id. | Required |
restId | string | The restaurant id. | Optional |
status | string | The new status of the order. See Status values. | Required |
reason | string | Cancellation reason code. Required when status is RESTAURANT_CANCELLED. See Cancellation reason. | Conditional |
reasonDetails | string | Free-text cancellation details. Required when reason is other. Must not be sent for any other reason. | Conditional |
finalPrepTime | integer | Final kitchen preparation time in minutes selected by the restaurant. Sent with RESTAURANT_ACCEPTED. When prepTimeDetails was present on the order, the value must stay within predictedPrepTime ± the given thresholds. | Optional |
Status values
| Value | Sent by | Meaning |
|---|---|---|
RESTAURANT_ACCEPTED | Your POS | The restaurant accepted the order. |
RESTAURANT_CANCELLED | Your POS | The restaurant cancelled the order. Requires a reason. |
FOOD_READY | Your POS | The food is ready. |
CUSTOMER_CANCELLED | Ownly | The customer cancelled the order. |
Cancellation reason
| Value | Meaning |
|---|---|
item_out_of_stock | One or more items required for the order are unavailable. |
store_closed | The restaurant is closed. |
store_busy | The restaurant cannot fulfil the order due to high load. |
other | The cancellation does not match any predefined reason. |
reasonis mandatory for a cancellation.- Only the documented enum values are accepted.
reasonDetailsis mandatory, and must be a non-empty string, whenreasonisother.
Sample requests
POST /api/v1/order-status key: <key> { "orderId": "1783513160580978958", "restId": "10454115", "status": "RESTAURANT_ACCEPTED", "finalPrepTime": 18 }
POST /api/v1/order-status key: <key> { "orderId": "1783513160580978958", "restId": "10454115", "status": "RESTAURANT_CANCELLED", "reason": "item_out_of_stock" }
POST /api/v1/order-status key: <key> "orderId": "1783513160580978958", "restId": "10454115", "status": "RESTAURANT_CANCELLED", "reason": "other", "reasonDetails": "Kitchen equipment is not operational" }
Responses
{
"message": "Order Status exchanged successfully"
}{
"message": "error message"
}Call masking.
Retrieve a masked contact number and OTP to start a call between two entities for an order. The from and to query parameters name who is calling whom.
Request headers
| Header | Description |
|---|---|
key | Key |
Accept | application/json |
Query parameters
| Parameter | Type | Description | Required |
|---|---|---|---|
orderId | string | Unique string identifier for the order. For example, "17277272828828". | Required |
from | string | Origin entity initiating the contact. For example, "restaurant". | Required |
to | string | Target entity receiving the contact. For example, "customer". | Required |
Response body
| Parameter | Type | Description | Required |
|---|---|---|---|
number | string | Masked contact number for the call. | Required |
otp | string | 6-digit PIN for call verification. | Required |
Sample request
curl --location 'https://api.baseurl.com/api/v1/contact?orderId=172282882929&from=restaurant&to=customer' \
--header 'Accept: application/json'Responses
{
"number": "1234567890",
"otp": "482901"
}{
"error": "error message"
}Rider status.
Ownly tells your system where the rider is on an order, from assignment to delivery. Expose this endpoint on your own host.
Request headers
| Header | Description |
|---|---|
key | Key |
Request body
| Parameter | Type | Description | Required |
|---|---|---|---|
orderId | string | Unique identifier for the order for which the rider status is being updated. | Required |
status | string | The current status of the rider for the order. See Status values. | Required |
riderDetails | Rider details object | The rider's name and phone number. | Required |
Status values
| Value | Meaning |
|---|---|
RIDER_ASSIGNED | A rider has been assigned to the order. |
RIDER_AT_STORE | The rider has reached the store. |
OUT_FOR_DELIVERY | The rider is on the way to the customer. |
REACHED_DROP_LOCATION | The rider has reached the drop location. |
DELIVERED | The order has been delivered. |
Rider details
| Parameter | Type | Description | Required |
|---|---|---|---|
name | string | The name of the assigned rider. For example, "Ram" is the delivery executive handling the order. | Required |
phone | string | The phone number of the rider. For example, "98******10". | Required |
Sample request
POST <upstream-host>/api/v1/rider-status key: <key> { "orderId": "10454115", "status": "OUT-FOR-DELIVERY", "riderDetails": { "name": "Ram", "phone": "9******210" } }
Responses
{
"message": "Delivery Status updated successfully."
}{
"error": "error message"
}Store status.
Enable or disable a store on Ownly. Take a restaurant offline when the kitchen is closed or overwhelmed, and bring it back when it is ready.
orderingEnabled flag decides whether the store accepts new orders.Request headers
| Header | Description |
|---|---|
key | Key |
Request body
| Parameter | Type | Description | Required |
|---|---|---|---|
restId | string | Unique identifier of the restaurant whose status is being updated. | Required |
orderingEnabled | boolean | The current status of the restaurant: whether it is accepting new orders. true means open for new orders. | Required |
nextAvailableAt | int | Unix timestamp, in seconds. | Optional |
reason | string | Reason for store closure. | Optional |
Sample request
POST /api/v1/store-status key: <key> { "restId": "b7hi36eg", "orderingEnabled": true }
Responses
{
"message": "Restaurant status successfully updated."
}{
"error": "error message"
}All endpoints.
Filter by name, path or parameter. Each call is hosted by one side, except order status, which both host.
Menu management
POST/api/v1/menuPush the full menuOwnlyPOST/api/v1/item-statusUpdate stock for items, variants and add-onsOwnlyOrder management
POST/api/v1/order/Receive a new order from OwnlyYour POSPOST/api/v1/order-statusExchange accepted, ready and cancelledBothGET/api/v1/contactGet a masked number and OTP for a callOwnlyRider management
POST<upstream-host>/api/v1/rider-statusReceive rider assignment through deliveryYour POSStore management
POST/api/v1/store-statusTurn ordering on or off for a storeOwnlyNo endpoint matches that search.
Change log.
Changes to the API contract and the documentation, newest first.
- Documented request headers (
key) for Rider status update under Rider management
- Added
ioosobject for collecting items andnextAvailableAtdata in the restaurant cancellation call under Order status exchange
- Added optional
prepTimeDetailsobject (predictedPrepTime,maxIncreaseThreshold,maxDecreaseThreshold) at order root level in Order relay - Added optional
finalPrepTimeforRESTAURANT_ACCEPTEDunder Order status exchange
- Added optional
discountsin the Order info object under Order relay
- Restaurant cancellation: API contract update for the
reasonenum andreasonDetailsunder Order status exchange
- Added Call masking API (
GET /api/v1/contact) under Order management
- Added
phoneNumber(masked) to the Customer object in Order relay - Added
otpobject (pickup,drop) at order root level in Order relay
- Added support for the
metaobject for storing auto-acceptance during order status exchange
- Added support for the
metaobject for storingrxLocation(restaurant latitude and longitude) in Menu push
- Updated the
riderDetailsobject in the Rider status API
- Fixed the
itemsfield name in the Order relay sample request body
- Changed
riderDatatoriderDetailsin the Rider status update API
- Changed
taxestotaxIdsin the item bill component - Added
gstTypeandtimingsin the item component
- Updated the enums for the rider status and order status APIs