Events
All webhook events share the same payload structure -- the top-level category field tells you what event fired, and the payload object contains the order at the time of the event. The key field to watch is payload.status, which reflects the order's current state.
Events reference
| Event | payload.status | Description |
|---|---|---|
ORDER_CREATED | preparing | A new order has been placed and payment confirmed |
ORDER_ASSIGNED | preparing | A rider has been assigned to collect the order |
ORDER_AWAITING_PICKUP | awaiting_pickup | The rider has arrived at your location and is waiting to collect |
ORDER_PICKED_UP | picked | The rider has collected the order and is heading to the customer |
ORDER_ARRIVED_AT_CUSTOMER_LOCATION | arrived | The rider has arrived at the customer's location |
ORDER_COMPLETE | completed | The order has been successfully delivered |
ORDER_ITEMS_UPDATED | accepted | An item was unavailable and the customer has confirmed the vendor's suggested replacement |
Item substitutions
When a vendor marks an item as unavailable and suggests a replacement, and the customer confirms the replacement, Chowdeck sends an ORDER_ITEMS_UPDATED event to your webhook URL.
The payload has the same structure as ORDER_CREATED. The items array reflects the current state of the order after substitution -- replaced items appear in the list, the original unavailable items do not.
There is no explicit flag on individual items to indicate they were substituted. To determine what changed, compare the items array against the original ORDER_CREATED payload, or inspect the timeline array for entries with action: "REPLACED_AN_ITEM".
{
"category": "ORDER_ITEMS_UPDATED",
"description": "The customer replaced some items",
"payload": {
"id": 1453,
"reference": "testing119312",
"status": "accepted",
"items": [
{
"id": 2409,
"item_id": 109,
"name": "Chicken Suya",
"description": "Grilled chicken suya",
"reference": "menu-ref-xyz",
"type": "item",
"pack_id": 1,
"quantity": 40,
"price_per_quantity": 52000
}
],
"timeline": [
{
"action": "REPLACED_AN_ITEM",
"description": "Vendor replaced an unavailable item",
"created_at": "2022-11-25T17:10:00.000Z"
}
]
}
}Payload field reference
Every event delivers the same order object in the payload field. Here's what each field means:
Order fields:
| Field | Type | Description |
|---|---|---|
id | integer | Internal order ID |
reference | string | Your order reference |
status | string | Current order status — use this to track order progress |
summary | string | Short text summary of the order items |
total_price | integer | Total order amount in the smallest currency unit |
delivery_price | integer | Delivery fee in the smallest currency unit |
currency | string | Currency code (e.g. NGN) |
source | string | How the order was placed (e.g. api) |
class | string | Order type (e.g. delivery) |
created_at | string | ISO 8601 timestamp when the order was created |
updated_at | string | ISO 8601 timestamp of the last update |
time_payment_confirmed | string | ISO 8601 timestamp when payment was confirmed |
time_customer_received_order | string | ISO 8601 timestamp when the customer received the order. null until delivered. |
actual_delivery_time | string | Actual delivery duration. null until delivered. |
driver | object | Assigned rider details. Empty object until a rider is assigned. |
Customer fields (customer):
| Field | Type | Description |
|---|---|---|
id | integer | Internal customer ID |
first_name | string | Customer's first name |
last_name | string | Customer's last name |
email | string | Customer's email address |
phone | string | Customer's phone number |
country_code | string | Customer's country code |
Items array (items[]):
| Field | Type | Description |
|---|---|---|
id | integer | Menu item ID |
item_id | integer | Internal item identifier |
name | string | Item name |
description | string | Item description |
reference | string | Menu or menu group reference |
type | string | item for standard items, group for variant/combo items |
pack_id | integer | Pack this item belongs to |
quantity | integer | Number of units ordered |
price_per_quantity | integer | Price per unit in the smallest currency unit |
variant_id | integer | Variant ID — only present when type is group |
variant_reference | string | Variant reference — only present when type is group |
variant_name | string | Variant name — only present when type is group |
Timeline array (timeline[]):
| Field | Type | Description |
|---|---|---|
action | string | The timeline action (e.g. ORDER_CREATED) |
description | string | Human-readable description of the action |
created_at | string | ISO 8601 timestamp of when the action occurred |
Address fields (customer_address, vendor_address):
| Field | Type | Description |
|---|---|---|
id | integer | Internal address ID |
street | string | Full street address |
pretty_name | string | Display-friendly address string |
city | string | City |
state | string | State |
country | string | Country |
coordinate.x | number | Longitude |
coordinate.y | number | Latitude |
Vendor fields (vendor_information):
| Field | Type | Description |
|---|---|---|
name | string | Vendor store name |
reference | string | Vendor reference |
webhook_url | string | Configured webhook URL for the vendor |
Sample payload
Here is a complete example of an ORDER_CREATED webhook:
{
"category": "ORDER_CREATED",
"description": "New order",
"payload": {
"id": 1453,
"reference": "testing119312",
"status": "preparing",
"summary": "40 portions of Beef.",
"total_price": 2130000,
"delivery_price": 80000,
"currency": "NGN",
"source": "api",
"class": "delivery",
"created_at": "2022-11-25T17:03:40.000Z",
"updated_at": "2022-11-25T17:03:55.000Z",
"time_payment_confirmed": "2022-11-25T17:03:43.000Z",
"time_customer_received_order": null,
"actual_delivery_time": null,
"driver": {},
"customer": {
"id": 70,
"first_name": "Dave",
"last_name": "Aluks",
"email": "[email protected]",
"phone": "08142272922",
"country_code": null
},
"items": [
{
"id": 2408,
"item_id": 108,
"name": "Beef Suya",
"description": "Pure beef meat",
"reference": "menu-ref-abc",
"type": "item",
"pack_id": 1,
"quantity": 40,
"price_per_quantity": 50000
}
],
"timeline": [
{
"action": "ORDER_CREATED",
"description": "Order created",
"created_at": "2022-11-25T17:03:40.000Z"
},
{
"action": "MADE_PAYMENT",
"description": "Made payment using none",
"created_at": "2022-11-25T17:03:42.000Z"
},
{
"action": "VENDOR_ACCEPTED_ORDER",
"description": "Vendor accepted the order",
"created_at": "2022-11-25T17:03:46.000Z"
}
],
"customer_address": {
"id": 531,
"street": "33 Adisa Coker St, Ojodu, Lagos",
"pretty_name": "33 Adisa Coker St, Ojodu, Lagos",
"city": "Ojodu",
"state": "Lagos",
"country": "NG",
"coordinate": {
"x": 3.3393804,
"y": 6.6568331
}
},
"vendor_address": {
"id": 531,
"street": "33 Adisa Coker St, Ojodu, Lagos",
"pretty_name": "33 Adisa Coker St, Ojodu, Lagos",
"city": "Ojodu",
"state": "Lagos",
"country": "NG",
"coordinate": {
"x": 3.3393804,
"y": 6.6568331
}
},
"vendor_information": {
"name": "Suya Spots",
"reference": "vendor-ref-001",
"webhook_url": "https://your-server.com/webhooks/chowdeck"
}
}
}The payload structure is the same across all events. Only
category,description, andpayload.statuschange between events.
Updated about 1 month ago
