Event stream
Order Events
The Innovorder platform fires two order webhook events: orders.paid and orders.cancelled. The orders.paid event is triggered whenever an order is successfully placed and paid for. The orders.cancelled event is triggered whenever a previously paid order is cancelled. Both events deliver the exact same OmnichannelOrder payload structure, differing only in the status field (PAID vs CANCELLED). This is the primary mechanism to inject orders into external systems and to keep them synchronized with cancellations.
Kiosk "pay at the counter" orders
An orders.paid delivery does not always mean the guest paid on the ordering channel. A kiosk order placed to be settled at the counter carries the reserved key metadata.kioskPaymentState set to "NOT_PAID_AT_KIOSK". When the restaurant has no POS device receiving kiosk orders, that sale is recorded through a synthetic external payment, so it reaches you as orders.paid with status: "PAID" and a payments[] entry of type "ExternalPayment".
The key is written once at order creation and never changes afterwards: it says where the guest was expected to pay, not whether the money has been collected. Read it, not status, to know whether a kiosk order was paid at the kiosk. See the full rule in Orders > Create Orders.
Retry Policy
Your server must return an HTTP 200 OK response code with an empty body to acknowledge receipt. If not, we will resend the webhook based on an exponential backoff schedule.
Note: We do not retry requests if your server responds with 401 Unauthorized or 404 Not Found.
Event Structure
Every order webhook delivery is wrapped in the following envelope:
{
"event_type": "orders.paid",
"event_id": "c4d2261e-2779-4eb6-beb0-cb41235c751e",
"event_time": 1427343990,
"payload": { ... }
}event_type: Either"orders.paid"or"orders.cancelled".event_id: HMAC-SHA256 hash that uniquely identifies this delivery. Use it for deduplication.event_time: Unix timestamp in milliseconds indicating when the event was generated.payload: The complete OmnichannelOrder object described below.
Complete Payload Example
Below is a full, realistic example of an orders.paid webhook delivery showing all key fields:
{
"event_type": "orders.paid",
"event_id": "a3f8c2d1e9b74056ab12cd34ef567890abcdef1234567890abcdef1234567890",
"event_time": 1711360200000,
"payload": {
"omnichannelOrderId": "98765432",
"reportOrderId": 987654321,
"orderUuid": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"brandId": 100,
"restaurantId": 200,
"customerId": 5001,
"userId": null,
"dailyOrderId": 42,
"status": "PAID",
"channelId": "2",
"consumptionModeId": 1,
"deviceId": "WEB-001",
"deviceName": "Web Ordering",
"seller": null,
"ticketNumber": "A042",
"tableName": null,
"comment": null,
"numberOfGuests": 1,
"currency": "EUR",
"startDate": "2026-03-25T12:30:00.000Z",
"lastUpdateDate": "2026-03-25T12:32:00.000Z",
"businessYear": 2026,
"businessMonth": 3,
"businessDay": 25,
"service": 0,
"shift": { "name": "Lunch" },
"totalPriceWithTaxIncluded": 1850,
"totalPriceWithTaxExcluded": 1542,
"totalPriceDiscountedWithTaxIncluded": 1550,
"totalPriceDiscountedWithTaxExcluded": 1292,
"totalTax": 258,
"totalDiscount": 300,
"turnover": 1550,
"totalAmountFree": 0,
"totalItemFree": 0,
"totalAmountCancelled": 0,
"totalItemCancelled": 0,
"items": [
{
"itemId": 5001,
"parentItemId": null,
"name": "Classic Burger",
"type": "PRODUCT",
"status": "VALIDATED",
"quantity": 1000,
"totalPriceWithTaxIncluded": 1200,
"originalUnitPrice": 1200,
"vatValue": 1000,
"skuValue": "BUR-001",
"free": false,
"tags": [{ "value": "Burger" }],
"categories": [{ "value": "Main Course" }],
"discounted": false,
"measurementUnit": "UNIT",
"measuredQuantity": 1
}
],
"payments": [
{
"type": "Card",
"label": "Visa",
"quantity": 1,
"value": 1550,
"luncheonCode": null,
"transactionId": null
}
],
"taxes": [
{
"taxRate": 1000,
"totalTax": 258,
"totalInclTax": 1550,
"totalExclTax": 1292
}
],
"discounts": [
{ "name": "SUMMER10", "value": 300 }
],
"fees": [
{
"name": "Delivery Fee",
"taxRate": 2000,
"quantity": 1,
"amount": 350,
"type": "Delivery"
}
],
"grants": [],
"entranceFees": [],
"loyaltyPrograms": [],
"pricingRule": null,
"customer": {
"phone": "+33612345678",
"email": "jean.dupont@example.com",
"firstName": "Jean",
"lastName": "Dupont",
"badgeNumber": null,
"disabledAt": null,
"student": null
},
"restaurant": {
"name": "Chez Yann",
"contactPhone": "0147689047",
"externalId": "SITE01_REST01",
"address": {
"streetNumber": "12",
"route": "Rue de la Paix",
"postalCode": "75002",
"locality": "Paris"
}
},
"deliveryAddress": {
"phone": "+33612345678",
"route": "45 Avenue des Champs-Elysees",
"postalCode": "75008",
"locality": "Paris",
"streetNumber": "45",
"additionalInfo": "3rd floor",
"digicode": "4521",
"apartmentNumber": "12B"
},
"photos": [],
"cancellationReason": null,
"cancellationReasonDescription": null,
"metadata": null
}
}OmnichannelOrder Payload Reference
The payload contains the complete details of the order. All monetary values are expressed in cents (e.g., 1850 = 18.50 EUR) unless otherwise noted. Below is a comprehensive field-by-field reference grouped by category.
Core Identifiers
| Field | Type | Description |
|---|---|---|
| omnichannelOrderId | String | Unique identifier of the order. |
| reportOrderId | Number | Numeric ID used in reporting and exports. |
| orderUuid | String (UUID) | UUID v4 identifier of the order. |
| brandId | Number | Unique identifier of the brand. |
| restaurantId | Number | Unique identifier of the restaurant. |
| customerId | Number | null | ID of the customer who placed the order, or null for anonymous orders. |
| userId | Number | null | ID of the authenticated user (e.g., POS operator), or null. |
| dailyOrderId | Number | Sequential order number for the current business day. |
| channelId | String (Enum) | Ordering channel: "1" = Kiosk, "2" = Web, "5" = POS. |
| consumptionModeId | Number (Enum) | Consumption mode: 1 = Delivery, 2 = Take Away, 3 = Sit In, 4 = Drive. |
| deviceId | String | null | Identifier of the device that created the order. |
| deviceName | String | null | Human-readable name of the device. |
| seller | String | null | Name of the seller/cashier, if applicable. |
| ticketNumber | String | null | Printed ticket number displayed to the customer (e.g., "A042"). |
| tableName | String | null | Table name for sit-in orders, or null. |
| comment | String | null | Free-text comment left by the customer. |
| numberOfGuests | Number | Number of guests for the order. |
| currency | String | ISO 4217 currency code (e.g., "EUR"). |
Timestamps
| Field | Type | Description |
|---|---|---|
| startDate | String (ISO 8601) | Timestamp when the order was created. |
| lastUpdateDate | String (ISO 8601) | Timestamp of the last modification to the order. |
| businessYear | Number | Fiscal year of the order. |
| businessMonth | Number | Fiscal month of the order (1-12). |
| businessDay | Number | Fiscal day of the order (1-31). |
| service | Number | Service period index (0-based). |
| shift.name | String | null | Name of the shift (e.g., "Lunch", "Dinner"). |
Status
| Field | Type | Description |
|---|---|---|
| status | String (Enum) | Order status: "PAID", "CANCELLED", or "VALIDATED". |
| cancellationReason | String | null | Reason code for cancellation. Present only when status is "CANCELLED". |
| cancellationReasonDescription | String | null | Human-readable description of the cancellation reason. |
| metadata | String | null | JSON-encoded metadata of the originating Web/Kiosk order, as sent on POST /orders (null when the order has no Web/Kiosk counterpart, e.g. a POS sale). The platform owns a single key inside it, kioskPaymentState, set to "NOT_PAID_AT_KIOSK" when a kiosk guest ordered to pay at the counter, which can happen while status already reads "PAID". Every other key is yours and is passed through untouched. |
Pricing (all values in cents)
| Field | Type | Description |
|---|---|---|
| totalPriceWithTaxIncluded | Number | Total price including tax, before discounts. |
| totalPriceWithTaxExcluded | Number | Total price excluding tax, before discounts. |
| totalPriceDiscountedWithTaxIncluded | Number | Total price including tax, after discounts. |
| totalPriceDiscountedWithTaxExcluded | Number | Total price excluding tax, after discounts. |
| totalTax | Number | Total tax amount. |
| totalDiscount | Number | Total discount amount applied to the order. |
| turnover | Number | Net revenue (total after discounts, tax included). |
| totalAmountFree | Number | Total value of free (complimentary) items. |
| totalItemFree | Number | Count of free items in the order. |
| totalAmountCancelled | Number | Total value of cancelled items. |
| totalItemCancelled | Number | Count of cancelled items in the order. |
Item Object
| Field | Type | Description |
|---|---|---|
| itemId | Number | Unique identifier of the item. |
| parentItemId | Number | null | ID of the parent item for sub-items (e.g., menu steps). null for top-level items. |
| name | String | Display name of the product. |
| type | String | Item type (e.g., "PRODUCT", "MENU", "STEP"). |
| status | String | Item status (e.g., "VALIDATED", "CANCELLED"). |
| quantity | Number | Quantity in thousandths (e.g., 1000 = 1 unit, 2500 = 2.5 units). |
| totalPriceWithTaxIncluded | Number | Total item price including tax (cents). |
| originalUnitPrice | Number | Original unit price before any discount (cents). |
| vatValue | Number | VAT rate in basis points (e.g., 1000 = 10.00%). |
| skuValue | String | null | SKU code of the product. |
| free | Boolean | Whether the item was given for free. |
| tags | Array | List of tag objects. Each has a value string. |
| categories | Array | List of category objects. Each has a value string. |
| discounted | Boolean | Whether a discount was applied to this item. |
| reduced | Boolean | undefined | Whether the item has a reduced price (e.g., pricing rule). |
| measurementUnit | String | Unit of measurement (e.g., "UNIT", "KG"). |
| measuredQuantity | Number | Human-readable quantity (e.g., 1 for 1 unit, 0.5 for 500g). |
Payment Object
| Field | Type | Description |
|---|---|---|
| type | String | Payment type: "Cash", "Card", "EWallet", "Change", etc. |
| label | String | null | Display label for the payment method (e.g., "Visa"). |
| quantity | Number | Number of payment units (typically 1). |
| value | Number | Payment amount in cents. |
| luncheonCode | String | null | Luncheon voucher code, if applicable. |
| transactionId | String | null | External transaction ID from the payment provider. |
Tax Object
| Field | Type | Description |
|---|---|---|
| taxRate | Number | Tax rate in basis points (e.g., 1000 = 10.00%, 2000 = 20.00%). |
| totalTax | Number | Total tax amount for this rate (cents). |
| totalInclTax | Number | Total amount including this tax (cents). |
| totalExclTax | Number | Total amount excluding this tax (cents). |
Fee Object
| Field | Type | Description |
|---|---|---|
| name | String | Name of the fee (e.g., "Delivery Fee"). |
| taxRate | Number | Tax rate applied to the fee (basis points). |
| quantity | Number | Number of fee units. |
| amount | Number | Fee amount in cents. |
| type | String | Fee type: "Delivery" or "Service". |
Discount Object
| Field | Type | Description |
|---|---|---|
| name | String | Name or code of the discount (e.g., "SUMMER10"). |
| value | Number | Discount amount in cents. |
Grant Object
| Field | Type | Description |
|---|---|---|
| labelTicket | String | Label printed on the ticket for the grant. |
| amount | Number | Unit grant amount in cents. |
| quantity | Number | Number of grant units. |
| totalAmount | Number | Total grant amount in cents (amount * quantity). |
EntranceFee Object
| Field | Type | Description |
|---|---|---|
| labelTicket | String | Label printed on the ticket for the entrance fee. |
| amount | Number | Unit entrance fee amount in cents. |
| vat | Number | VAT rate applied to the entrance fee (basis points). |
| type | String | Type of entrance fee. |
| totalTaxEntranceFee | Number | Total tax amount for the entrance fee (cents). |
| quantity | Number | Number of entrance fee units. |
| totalAmount | Number | Total entrance fee amount in cents. |
Customer Object
| Field | Type | Description |
|---|---|---|
| phone | String | null | Customer's phone number. |
| String | null | Customer's email address. | |
| firstName | String | null | Customer's first name. |
| lastName | String | null | Customer's last name. |
| badgeNumber | String | null | RFID/NFC badge number. |
| disabledAt | String | null | Timestamp when the customer account was disabled, or null if active. |
| student | Object | null | Student information object containing class, section, subSection, and studentNumber. |
| balanceInformation | Object | null | E-Wallet balance info containing ewalletBalanceBeforeOrder and ewalletBalanceAfterOrder (cents). |
Restaurant Object
| Field | Type | Description |
|---|---|---|
| name | String | Restaurant name. |
| contactPhone | String | null | Restaurant contact phone number. |
| externalId | String | null | External identifier for the restaurant (used for third-party integrations). |
| address.streetNumber | String | null | Street number of the restaurant address. |
| address.route | String | null | Street name. |
| address.postalCode | String | null | Postal/ZIP code. |
| address.locality | String | null | City name. |
| address.country | String | null | Country code or name. |
Delivery Address
| Field | Type | Description |
|---|---|---|
| phone | String | null | Contact phone number for delivery. |
| streetNumber | String | null | Street number. |
| route | String | null | Street name. |
| postalCode | String | null | Postal/ZIP code. |
| locality | String | null | City name. |
| additionalInfo | String | null | Additional delivery instructions (e.g., "3rd floor"). |
| digicode | String | null | Building entry code. |
| apartmentNumber | String | null | Apartment or unit number. |
Note: Object Mapping for Students
For student account integrations, mapping specific fields is often required.
// Example JS extraction
const payload = event.payload;
const mapping = {
badgeNumber: payload.customer.badgeNumber,
registrationNumber: payload.customer.student.studentNumber, // Matricule
accountId: payload.customerId, // ID Convive
siteId: payload.restaurant.externalId.split('_')[0]
};Note: The OmnichannelOrder payload is the same structure returned by GET /v1/orders. See Retrieve Orders for query parameters and filtering options.