API Reference

🪝Webhooks API

Overview

The Kitchenhub API includes webhooks for incoming orders and store notifications. In order for your service to receive webhooks from Kitchenhub, set your webhook URL and rules via webhook API. It is also possible to set up multiple webhooks if you need them.

Type of webhook notifications

The following types of notification are supported: Order, MenuIntegrationStatus, IntegrationAccount, IntegrationAccountOnlineStatus, Delivery, Cook.

If you need to get real-time order notifications and update its status you have to get Order notification.
You can manage what type of orders you want to get and in which statuses by managing the setting of a webhook via webhook API. For example, you can use it, if you need to get orders only in new status and only if they are for delivery, but not for pickup.

You can also get other types of notifications when stores are going offline on the provider side, integration account is deactivated or menu integration status is changed.

Retry policy

If a webhook delivery fails, KitchenHub retries it once. Each event is delivered at most twice: the initial attempt and one retry.

A delivery is retried when:

  • your endpoint responds with a 4xx or 5xx status;
    the request fails, for example with a DNS, connection or SSL error, or a timeout.
  • A 2xx response is treated as delivered, and no retry is sent.

The retry is sent immediately after the failed attempt, with no delay. If the retry also fails, the event is not delivered again.

KitchenHub waits up to 10 seconds for each phase of the request: connect, write and read. Respond with a 2xx status as soon as the event is received, and continue processing asynchronously if it takes longer.

The same event may be delivered twice, so make your webhook handler idempotent.

Order notification

Event type is Order.

Event status may take one of the following values: OrderCreated, OrderUpdated.

The section Ordercontains the order data.

Example

{
   "version":"2.0.0",
   "event_data":{
      "event_type":"Order",
      "status":"OrderUpdated"
   },
   "order":{
      "order":{
         "id":6316634709688320,
         "external_id":"99fc40a4-fa10-4703-9cfc-230c3aa5b287",
         "number":"86f0bbdf",
         "daily_number":11,
         "type":"delivery",
         "status":"cancelled",
         "notes":null,
         "paid":true,
         "asap":true,
         "add_disposable_items":false,
         "prep_time_minutes":null,
         "table_number":null,
         "cancelled_by":"not accepted"
      },
      "provider":{
         "id":"doordash_pos",
         "name":"doordash_pos",
         "merchant_id":"0ba73df4-bd12-421a-8e51-ef64c7350268",
         "store_id":null
      },
      "store":{
         "id":"e6f5206e-6939-4b3d-82c4-0e7bde09c4e8",
         "name":"Nikki's store",
         "partner_store_id":null
      },
      "customer":{
         "name":"Test Customer",
         "email":null,
         "phone_number":"8552228111",
         "phone_code":null
      },
      "items":[
         {
            "id":"3082240d-26ff-4462-94d4-bbfccdf42b52",
            "partner_id":"3082240d-26ff-4462-94d4-bbfccdf42b52",
            "name":"Test Item1",
            "quantity":1,
            "price":"2.0",
            "base_price":"2.0",
            "instructions":"Item for TEST",
            "is_alcohol":false,
            "options":[
               {
                  "id":"c4949f63-a157-4bd0-9f84-f776d9dba390",
                  "partner_id":"c4949f63-a157-4bd0-9f84-f776d9dba390",
                  "name":"Test option1",
                  "quantity":1,
                  "price":"0.0",
                  "base_price":"0.0",
                  "modifier_name":"Test modifier1",
                  "options":[]
               }
            ]
         }
      ],
      "delivery":{
         "type":"provider",
         "status":null,
         "notes":null,
         "address":{
            "country":null,
            "street":null,
            "city":null,
            "state":null,
            "zipcode":null,
            "unit_number":null,
            "latitude":null,
            "longitude":null
         },
         "full_address":null,
         "courier":{
            "name":null,
            "photo_url":null,
            "phone_number":null,
            "status":"pending"
         },
         "service":null,
         "cancellation_reason":null
      },
      "payment":{
         "method":"ONLINE"
      },
      "charges":{
         "subtotal":"2.0",
         "tax":"0.17",
         "tax_payout":"0.17",
         "restaurant_tip_amount":"0.0",
         "adjustment":null,
         "tips":"0.0",
         "discount":"0.0",
         "total":"2.17",
         "delivery_fee":null,
         "service_fee":null,
         "processing_fee":null,
         "commission":null,
         "payout":null,
         "other_fee":{}
      },
      "timestamps":{
         "placed_at":"2025-04-22T13:12:18.031201Z",
         "created_at":"2025-04-22T13:12:18.589083Z",
         "pickup_at":"2025-04-22T13:19:53Z",
         "accepted_at":null,
         "cancelled_at":"2025-04-22T13:18:02.289876Z",
         "completed_at":null,
         "delivery_at":null,
         "scheduled_for":null
      },
      "location":{
         "id":"e2634686-7717-41b7-b545-cb40da3a6c04",
         "partner_location_id":null,
         "name":"Test Location1",
         "street":"100 N Centre Ave",
         "city":"Rockville Centre",
         "state":"NY",
         "zipcode":"11570",
         "lat":null,
         "lon":null
      }
   }
}

Menu integration status notification

Webhook type is MenuIntegrationStatus.

Event name may have only value MenuIntegrationStatusUpdated

The field menu_integration_status_data.status may take one of the following values: waiting, in_progress, completed, failed.
If the value of menu_integration_status_data.status is failedthen the field failed_reason will contain the reason description.

Example

{
   "event_data":{
      "webhook_type":"MenuIntegrationStatus",
      "event_name":"MenuIntegrationStatusUpdated",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"2b1561e5-74d8-49b4-9f09-c89f4f3f11f4",
      "proxy_restaurant_id":"4beb760c-9bf9-4938-9acf-94f515785397",
      "partner_store_id":null
   },
   "menu_integration_status_data":{
      "partner_menu_id":"2b1561e5-74d8-49b4-9f09-c89f4f3f11f4",
      "menu_name":"Test Menu",
      "provider_id":"foodhub",
      "status":"completed",
      "failed_reason":null
   }
}

Integration account notification

Webhook type is IntegrationAccount.

Event name may have one of the values: AccountCreated, AccountConnectionStatusChanged, AccountDeactivated, AccountRemoved.

This webhook is triggered when an integration account (a connection of a store to a provider) is created, changes its connection status, or is removed.

Events

Event nameWhen it is sent
AccountCreatedA new integration account is created: the store starts connecting to a provider. connection_status is in_progress, or waiting_menu when the provider requires a menu and the store has none.
AccountConnectionStatusChangedThe connection status changes to any value other than disabled, for example the connection is completed and the status becomes connected.
AccountDeactivatedThe connection status changes to disabled: the integration account is deactivated. Typically occurs when the provider blocks or disables the account, the integration connection is terminated by the provider, or the integration account is disabled in KitchenHub.
AccountRemovedThe integration account is removed while the store stays in KitchenHub: the integration is disconnected by a user or through the KitchenHub API, or the account is replaced by a new one. connection_status is null.

Connection status values

ValueMeaning
in_progressThe integration account is created and the connection is in progress, for example the restaurant has not yet authorized it on the provider's side.
waiting_menuThe connection is on hold: the provider requires a menu, and the store had no menu in KitchenHub when the integration account was created.
waitingThe connection is waiting for activation on the provider's side, for example a manual activation by the provider.
waiting_menu_mappingThe POS is connected, and the menu has to be mapped to the POS catalog.
action_requiredThe restaurant has to complete a step to finish the integration; connection_status_comment says what to do.
rejectedThe provider rejected the connection; connection_status_comment may carry the reason.
connectedThe connection is completed.
disabledThe integration account is deactivated.

Fields of integration_account_data

FieldTypeDescription
connection_status_commentstring or nullComment on the current status, when one is available: the deactivation reason reported by the provider (for example INVALID_CREDENTIALS), the reason of rejected, the step required for action_required. May be null, for example when the integration account was deactivated in KitchenHub. Always null for AccountRemoved.
provider_idstringProvider id in KitchenHub, for example ubereats, doordash, grubhub_pos.
provider_store_idstring or nullStore id on the provider's side. Usually null until the connection is completed.
connection_statusstring or nullConnection status after the change, see Connection status values. null for AccountRemoved: the integration account no longer exists.
account_idstringIntegration account id.
dashboard_urlstring or nullReserved, currently always null.
timestampstringWhen the change was saved in KitchenHub, ISO 8601 UTC with second precision: YYYY-MM-DDTHH:MM:SSZ. For AccountCreated it is the time the integration account was created, for AccountRemoved the time it was removed.

Filtering

The filters of a webhook configuration are matched against the fields of integration_account_data, the same way order filters are matched against order fields. For example, {"provider_id": ["ubereats"]} delivers only the events of Uber Eats integration accounts. An empty filters object delivers every event.

A filter key is skipped when the event's field is null, so the event is delivered. AccountRemoved has connection_status: null, so {"connection_status": ["disabled"]} delivers deactivations and every removal.

Examples

An Uber Eats integration account was created, and the connection started:

{
   "event_data":{
      "webhook_type":"IntegrationAccount",
      "event_name":"AccountCreated",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"74659e82-ae12-4bba-b1e0-cb7124a2d100",
      "proxy_restaurant_id":"3f7ac076-089d-4d00-97fa-bb3cd7640200",
      "partner_store_id":null
   },
   "integration_account_data":{
      "connection_status_comment":null,
      "provider_id":"ubereats",
      "provider_store_id":null,
      "connection_status":"in_progress",
      "account_id":"5f2c8e0b9a4d4c1e8b7a6d5c4b3a2f10",
      "dashboard_url":null,
      "timestamp":"2026-10-27T12:00:05Z"
   }
}

The connection was completed:

{
   "event_data":{
      "webhook_type":"IntegrationAccount",
      "event_name":"AccountConnectionStatusChanged",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"74659e82-ae12-4bba-b1e0-cb7124a2d100",
      "proxy_restaurant_id":"3f7ac076-089d-4d00-97fa-bb3cd7640200",
      "partner_store_id":null
   },
   "integration_account_data":{
      "connection_status_comment":null,
      "provider_id":"ubereats",
      "provider_store_id":"f0e1d2c3-b4a5-4697-8879-6a5b4c3d2e1f",
      "connection_status":"connected",
      "account_id":"5f2c8e0b9a4d4c1e8b7a6d5c4b3a2f10",
      "dashboard_url":null,
      "timestamp":"2026-10-27T12:03:41Z"
   }
}

The provider invalidated the credentials of a DoorDash integration account:

{
   "event_data":{
      "webhook_type":"IntegrationAccount",
      "event_name":"AccountDeactivated",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"74659e82-ae12-4bba-b1e0-cb7124a2d100",
      "proxy_restaurant_id":"3f7ac076-089d-4d00-97fa-bb3cd7640200",
      "partner_store_id":null
   },
   "integration_account_data":{
      "connection_status_comment":"INVALID_CREDENTIALS",
      "provider_id":"doordash",
      "provider_store_id":"111",
      "connection_status":"disabled",
      "account_id":"81673c1dd9e840ed99e82464ce4a00e2",
      "dashboard_url":null,
      "timestamp":"2026-10-27T15:20:00Z"
   }
}

The Uber Eats integration was disconnected in KitchenHub:

{
   "event_data":{
      "webhook_type":"IntegrationAccount",
      "event_name":"AccountRemoved",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"74659e82-ae12-4bba-b1e0-cb7124a2d100",
      "proxy_restaurant_id":"3f7ac076-089d-4d00-97fa-bb3cd7640200",
      "partner_store_id":null
   },
   "integration_account_data":{
      "connection_status_comment":null,
      "provider_id":"ubereats",
      "provider_store_id":"f0e1d2c3-b4a5-4697-8879-6a5b4c3d2e1f",
      "connection_status":null,
      "account_id":"5f2c8e0b9a4d4c1e8b7a6d5c4b3a2f10",
      "dashboard_url":null,
      "timestamp":"2026-10-27T16:05:12Z"
   }
}

Integration account online status notification

Webhook type is IntegrationAccountOnlineStatus.

Event name may have only value AccountOnlineStatusChanged.

This webhook is triggered when the online status of an integration account (a store on a delivery provider) changes: the store is paused and goes offline, or is resumed and goes back online. The change may be made in KitchenHub or on the provider's side; the field online_status_data.source tells which.

Typically occurs when:

  • A user pauses or resumes the store in the KitchenHub admin or app (source is user).
  • The store is paused or resumed through the KitchenHub public API, PUT /v2/integration_accounts/{integration_id}/status/ (source is api).
  • KitchenHub pauses or resumes the store automatically: orders were cancelled or expired, the location was archived, the company was blocked (source is system).
  • The store is paused or resumed on the provider's side, by the restaurant in the provider's dashboard or tablet, or by the provider itself (source is provider). Supported for Uber Eats, DoorDash and Grubhub.

The webhook is not sent when a store is closed by its working hours or closing days: a schedule is not a status change.

When the event is sent

One event is sent per actual status change:

  • online -> offline and offline -> online;
  • offline -> offline when the end of the pause changes, for example a new pause with a different duration or an extended pause.

Repeating the same status does not produce a new event.

DoorDash and GrubHub do not report when a paused store comes back online, so KitchenHub checks the status of paused DoorDash and GrubHub stores every 5 minutes. The online event may therefore arrive up to 5 minutes after the store was resumed, and its timestamp is the time the change was detected.

Fields of online_status_data

FieldTypeDescription
online_statusstringonline or offline.
account_idstringIntegration account id.
provider_idstringProvider id in KitchenHub, for example ubereats, doordash_pos, grubhub_pos.
sourcestringWho initiated the change: user, api, system or provider. See the values below.
offline_reason_codestring or nullMachine-readable trigger of the pause. Set only when online_status is offline; null when the store goes online. See the values below.
offline_reasonstring or nullHuman-readable reason of the pause, when one is available. For a pause made on the provider's side it carries the provider's own reason, for example PAUSED_BY_RESTAURANT. null when the store goes online or no text was given.
pause_duration_secondsinteger or nullSeconds from timestamp until the store is expected to come back online. null when the store goes online or the pause has no scheduled end. A pause set in KitchenHub without a duration lasts until the end of the store's day, and the value is the number of seconds until then.
timestampstringWhen the status change was confirmed, ISO 8601 UTC with second precision: YYYY-MM-DDTHH:MM:SSZ. For a change made on the provider's side it is the time of the provider's event, when the provider reports one.

source values

ValueMeaning
userA user changed the status in the KitchenHub admin or app.
apiThe status was changed through the KitchenHub public API.
systemKitchenHub automation: auto-pause after cancelled orders, location archive, company block.
providerThe change was made on the provider's side: by the restaurant in the provider's dashboard or tablet, or by the provider itself.

offline_reason_code values

ValueMeaningSent with source
manual_pauseManual pause by a user or through the API.user, api
order_cancellationsAutomatic pause after orders were cancelled or expired.system
tablet_offlineConnection to the tablet app was lost.system
inactivityA DoorDash store was paused for inactivity.system
location_archivedThe location was archived in KitchenHub.system
company_blockedThe company account was blocked, for example for non-payment; applies to all its locations.system
provider_pauseThe store was paused on the provider's side, by the restaurant or by the provider.provider
unknownThe reason was not provided or could not be mapped.any

Filtering

The filters of a webhook configuration are matched against the fields of online_status_data, the same way order filters are matched against order fields. For example, {"source": ["provider"]} delivers only the changes made on the provider's side, and {"online_status": ["offline"]} only pauses. An empty filters object delivers every event.

Examples

A user paused the store for one hour in the KitchenHub admin:

{
   "event_data":{
      "webhook_type":"IntegrationAccountOnlineStatus",
      "event_name":"AccountOnlineStatusChanged",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"acdf0ea1-3c42-4dae-aecf-12ad3a7d3000",
      "proxy_restaurant_id":"723122c1-1c73-4433-a49e-ab1f452d8000",
      "partner_store_id":null
   },
   "online_status_data":{
      "online_status":"offline",
      "account_id":"21229afe5048488cb09c105bac269000",
      "provider_id":"ubereats",
      "source":"user",
      "offline_reason_code":"manual_pause",
      "offline_reason":null,
      "pause_duration_seconds":3600,
      "timestamp":"2026-09-18T12:34:56Z"
   }
}

The store was resumed through the public API:

{
   "event_data":{
      "webhook_type":"IntegrationAccountOnlineStatus",
      "event_name":"AccountOnlineStatusChanged",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"acdf0ea1-3c42-4dae-aecf-12ad3a7d3000",
      "proxy_restaurant_id":"723122c1-1c73-4433-a49e-ab1f452d8000",
      "partner_store_id":"store-42"
   },
   "online_status_data":{
      "online_status":"online",
      "account_id":"5c0b0d1a4f0e4a6e9d3b2f1c8e7a6000",
      "provider_id":"doordash_pos",
      "source":"api",
      "offline_reason_code":null,
      "offline_reason":null,
      "pause_duration_seconds":null,
      "timestamp":"2026-09-18T13:00:02Z"
   }
}

The restaurant paused the store for 30 minutes in the Uber Eats dashboard:

{
   "event_data":{
      "webhook_type":"IntegrationAccountOnlineStatus",
      "event_name":"AccountOnlineStatusChanged",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"acdf0ea1-3c42-4dae-aecf-12ad3a7d3000",
      "proxy_restaurant_id":"723122c1-1c73-4433-a49e-ab1f452d8000",
      "partner_store_id":null
   },
   "online_status_data":{
      "online_status":"offline",
      "account_id":"21229afe5048488cb09c105bac269000",
      "provider_id":"ubereats",
      "source":"provider",
      "offline_reason_code":"provider_pause",
      "offline_reason":"PAUSED_BY_RESTAURANT",
      "pause_duration_seconds":1800,
      "timestamp":"2026-09-18T15:22:09Z"
   }
}

Delivery notification

Webhook type is Delivery.

Event name may take one of the following values: DeliveryCreated, DeliveryUpdated, QuoteCreated.

Example

{
   "event_data":{
      "webhook_type":"Delivery",
      "event_name":"DeliveryUpdated",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"ea5f5110-5455-4b35-9000-e12e994ad000",
      "proxy_restaurant_id":"05594593-4626-4800-a1cf-3d08d8c93000",
      "partner_store_id":"123"
   },
   "delivery_data":{
      "id":123123,
      "order_id":"cart-01",
      "order_number":null,
      "order_external_id":null,
      "scheduled_order":false,
      "delivery_order_id":"4a20d80e05944a8eaa21fa2558e31000",
      "cancellation_reason":"store_closed",
      "pickup_info":{
         "restaurant_name":"Test Restaurant",
         "restaurant_address":"368 E Campbell Ave, Campbell, California 95008",
         "pickup_datetime":"2025-11-18T18:26:25.669000+00:00",
         "pickup_notes":null,
         "store_name":"Test Restaurant",
         "store_address":"368 E Campbell Ave, Campbell, California 95008",
         "estimated_pickup_at":null
      },
      "customer_info":{
         "first_name":"Joe",
         "last_name":"Doe",
         "phone_number":"000111000",
         "email":null
      },
      "drop_off_info":{
         "drop_off_address":"368E Campbell Ave, Campbell, CA, 95008, USA",
         "drop_off_datetime":null,
         "drop_off_notes":"Dropoff notes",
         "estimated_dropoff_at":null
      },
      "charges":{
         "total":10,
         "delivery_fee":6.25,
         "delivery_tips":100,
         "subtotal":null
      },
      "status":"cancelled",
      "provider_id":null,
      "courier_info":{
         "id":null,
         "name":"",
         "phone_number":null,
         "phone_code":null,
         "photo_url":null,
         "vehicle_type":null
      },
      "delivery_type":"restaurant",
      "tracking_url":null,
      "created_at":"2025-11-18T18:16:38.907966",
      "delivered_at":null,
      "canceled_at":"2025-11-18T18:54:30.040889",
      "accepted_at":null,
      "is_mock_delivery":false,
      "items":[
         {
            "name":"Test item1",
            "quantity":1,
            "price":"9",
            "is_alcohol":false
         }
      ],
      "store_id":"ea5f5110-5455-4b35-9000-e12e994ad000",
      "virtual_brand_company_id":"Test Company",
      "delivery_provider_id":"doordash_drive",
      "delivery_at":null
   }
}

Cook notification

Webhook type is Cook.

Event name may have only value OrderCook.

Example

{
   "event_data":{
      "webhook_type":"Cook",
      "event_name":"OrderCook",
      "version":1
   },
   "restaurant_data":{
      "restaurant_id":"adf7a8e2-50d9-4a74-bd81-969e86870000",
      "proxy_restaurant_id":"9ab8cc76-367a-429f-9a7e-8504eab95000",
      "partner_store_id":null
   },
   "cook_data":{
      "order_id":123123,
      "distance":500.0,
      "order_number":"333444",
      "provider_id":"doordash_pos"
   }
}