Webhooks
Webhooks allow applications to receive, via HTTP requests, information about when something happens in GoTab in realtime. Examples include receiving a webhook event when a product has been updated, a new order is submitted, or the fiscal day has ended at a location.
Webhook endpoints, headers, and events can be configured on the integrations dashboard.
Webhook Payload Common Properties
Section titled “Webhook Payload Common Properties”All webhook URLs will be POSTed to with a Content-Type header value of application/json and a JSON formatted payload object with the following properties:
| Key | Type | Optional | Description |
|---|---|---|---|
| type | string | No | The event type. Examples include PRODUCT_UPDATED, ORDER_PLACED, and ITEM_ADDED. |
| targetUuid | string | Yes | A UUID provided only if the type of event targets a particular resource. For ORDER_PLACED this would be an orderUuid. |
| targetId | string | Yes | An ID provided for events where the target does not have a UUID. For CATEGORY_UPDATED this would be a categoryId. |
| locationUuid | string | Yes | The UUID of the location the event occurred at. |
| locationName | string | Yes | The name of the location the event occurred at. |
| locationId | string | Yes | The ID of the location the event occurred at. |
| createdAt | string | No | An ISO 8601 timestamp for the exact time the event was created. |
| data | object | No | The data for the event. The shape of the data varies based on the event being sent. |
The payload’s data, targetUuid, and targetId properties will vary depending on the event type.
Delivery Headers
Section titled “Delivery Headers”In addition to any custom headers configured on the dashboard, the POST request will contain the following headers:
| Key | Description |
|---|---|
| X-GoTab-Event-Type | The event type as a header. |
| X-GoTab-Event-Target-UUID | The event targetUuid as a header. |
| X-GoTab-Event-Target-ID | The event targetId as a header. |
| X-GoTab-Application-ID | The unique identifier of the application configured to receive the webhook event. This value will match the value shown on the integration dashboard page. |
| X-GoTab-Signature | If the webhook is configured with a secret then this value will be the SHA-256 HMAC of the request body encoded using the provided secret. |
The User-Agent for all webhook requests will start with GoTab-WebhookAgent.
Signature Verification
Section titled “Signature Verification”If a secret is configured on your webhook, the X-GoTab-Signature header will contain a hex-encoded SHA-256 HMAC of the raw JSON request body, signed with your secret. To verify the signature:
- Read the raw request body as a string (before JSON parsing).
- Compute
HMAC-SHA256(body, secret)and hex-encode the result. - Compare it to the
X-GoTab-Signatureheader value.
Example Request
Section titled “Example Request”POST /webhook/endpoint HTTP/2
Host: localhost:5000User-Agent: GoTab-WebhookAgent/1.0Content-Type: application/jsonX-GoTab-Event-Type: ORDER_PLACEDX-GoTab-Event-Target-UUID: ord_xxxxxxxxxX-GoTab-Event-Target-ID: 12345X-GoTab-Application-ID: int_xxxxxxxX-GoTab-Signature: [SHA-256 HMAC HEX]
{ "type": "ORDER_PLACED", "targetUuid": "ord_xxxxxxxxx", "targetId": "12345", "locationUuid": "loc_xxxxxxxxx", "locationName": "Main Street Location", "locationId": "67890", "createdAt": "2023-01-01T00:00:00.000Z", "data": { ... }}Events
Section titled “Events”Item Added
Section titled “Item Added”Fired whenever an item is successfully added to an order.
type: ITEM_ADDED
targetUuid: itemUuid
| Key | Type | Description |
|---|---|---|
| orderId | string | The ID of the order the item was added to. |
| productId | string | The ID of the product added. |
| name | string | The name of the item. |
| productName | string | The name of the product. |
| categoryName | string | The category the item belongs to. |
| quantity | number | The quantity added. |
| price | number | The price of the item. |
| tags | string[] | Tags associated with the item. |
| tabId | string | The ID of the tab the item was added to. |
| tabUuid | string | The UUID of the tab the item was added to. |
Item Removed
Section titled “Item Removed”Fired whenever an item is removed from an order.
type: ITEM_REMOVED
targetUuid: itemUuid
| Key | Type | Description |
|---|---|---|
| orderId | string | The ID of the order the item was removed from. |
| name | string | The name of the item. |
| productName | string | The name of the product. |
| quantity | number | The quantity removed. |
| price | number | The price of the item. |
| tags | string[] | Tags associated with the item. |
| tabId | string | The ID of the tab the item was removed from. |
| tabUuid | string | The UUID of the tab the item was removed from. |
Open Tab
Section titled “Open Tab”Fired whenever a tab is opened at a location.
type: OPEN_TAB
targetUuid: tabUuid
| Key | Type | Description |
|---|---|---|
| name | string | The name of the tab. |
| spotName | string | The name of the spot where the tab was opened. |
| total | number | The current tab total. |
| openedFrom | string | The context in which the tab was opened. Known values: SERVICE_MENU, SERVER_TAB. |
Close Tab
Section titled “Close Tab”Fired whenever a tab is closed at a location.
type: CLOSE_TAB
targetUuid: tabUuid
Data: None
Order Placed
Section titled “Order Placed”Fired whenever an order has been placed at a location.
type: ORDER_PLACED
targetUuid: orderUuid
| Key | Type | Description |
|---|---|---|
| created | string | ISO 8601 timestamp of when the order was created. |
| orderName | string | The name/label of the order. |
| scheduled | boolean | Whether the order is scheduled for a future time. |
| zoneName | string | The name of the zone where the order was placed. |
| spotName | string | The name of the spot where the order was placed. |
| zoneTags | string[] | Tags associated with the zone. |
| zoneGroupName | string | The name of the zone group. |
| total | number | The order total, including taxes and fees. |
| tabUuid | string | The UUID of the tab this order belongs to. |
| itemNames | string[] | A full list of item names from the order. |
| itemTags | string[] | A full list of item tags the order contains. |
| categoryNames | string[] | A full list of category names represented in the order. |
Guest Verified
Section titled “Guest Verified”Fired whenever a guest successfully verifies their identity at a location (e.g. after a phone verification flow).
type: GUEST_VERIFIED
targetUuid: customerUuid
| Key | Type | Description |
|---|---|---|
| oldCustomerId | string | The previous customer ID if the guest was merged with an existing record. |
| isFirstTime | boolean | Whether this is the first time the guest has verified at this location. |
Guest Subscribed
Section titled “Guest Subscribed”Fired whenever a guest subscribes to a location (e.g. opts into marketing communications).
type: GUEST_SUBSCRIBED
targetUuid: customerUuid
| Key | Type | Description |
|---|---|---|
| handle | string | The handle (e.g. phone number or email) the guest subscribed with. |
Guest Unsubscribed
Section titled “Guest Unsubscribed”Fired whenever a guest unsubscribes from a location.
type: GUEST_UNSUBSCRIBED
targetUuid: customerUuid
| Key | Type | Description |
|---|---|---|
| handle | string | The handle (e.g. phone number or email) the guest unsubscribed with. |
Menu Updated
Section titled “Menu Updated”Fired whenever a menu at a location is updated.
type: MENU_UPDATED
targetUuid: menuUuid
Data: None
Product Updated
Section titled “Product Updated”Fired whenever a product at a location is updated.
type: PRODUCT_UPDATED
targetUuid: productUuid
Data: None
Category Updated
Section titled “Category Updated”Fired whenever a category at a location is updated or when a product within that category is updated. The cause property describes the chain of events that triggered this event.
type: CATEGORY_UPDATED
targetUuid: null — categories do not have a UUID. Use targetId instead.
targetId: categoryId
| Key | Type | Description |
|---|---|---|
| cause | object | The update that triggered this category event. If a product change caused it, this will be { "type": "PRODUCT_UPDATED" }. |
Location Updated
Section titled “Location Updated”Fired whenever a location’s settings or details are updated.
type: LOCATION_UPDATED
targetUuid: locationUuid
Data: None
QR Scanned
Section titled “QR Scanned”Fired whenever a QR code is scanned at a location. This event is throttled to once per 5 minutes per customer per target to avoid duplicate events from repeated scans.
type: QR_SCANNED
targetId: spotId (or the ID of whichever resource the QR code points to)
| Key | Type | Description |
|---|---|---|
| type | string | The type of resource the QR code targets. Currently always SPOT. |
| targetName | string | The name of the resource the QR code points to. |
| entryPoint | string | The entry point context in which the QR code was scanned. |
Event Reference
Section titled “Event Reference”| Event Type | targetUuid | targetId | Has Data |
|---|---|---|---|
ITEM_ADDED | itemUuid | — | Yes |
ITEM_REMOVED | itemUuid | — | Yes |
OPEN_TAB | tabUuid | — | No |
CLOSE_TAB | tabUuid | — | No |
ORDER_PLACED | orderUuid | — | Yes |
GUEST_VERIFIED | customerUuid | — | Yes |
GUEST_SUBSCRIBED | customerUuid | — | Yes |
GUEST_UNSUBSCRIBED | customerUuid | — | Yes |
MENU_UPDATED | menuUuid | — | No |
PRODUCT_UPDATED | productUuid | — | No |
CATEGORY_UPDATED | null | categoryId | Yes |
LOCATION_UPDATED | locationUuid | — | No |
QR_SCANNED | — | spotId | Yes |
Retry behavior
Section titled “Retry behavior”GoTab retries webhook deliveries when your endpoint returns a non-2xx response or times out. Retries use exponential backoff over approximately 24 hours before the event is considered permanently failed.
To avoid missed events:
- Return a
2xxresponse as quickly as possible — do heavy processing asynchronously (queue the payload, respond immediately) - Your endpoint has a 10-second timeout — responses that take longer are treated as failures
- Design your handler to be idempotent — the same event may be delivered more than once
Testing webhooks locally
Section titled “Testing webhooks locally”Use a tunneling tool to expose a local server and register it as your webhook endpoint in the Integration Dashboard.
ngrok:
ngrok http 3000# Gives you: https://abc123.ngrok.io → forward to localhost:3000cloudflared:
cloudflared tunnel --url http://localhost:3000Register the public URL as your webhook endpoint, then trigger events by interacting with your sandbox location. Verify the X-GoTab-Signature header in your handler:
import crypto from 'crypto';
function verifySignature(rawBody, secret, signatureHeader) { const expected = crypto .createHmac('sha256', secret) .update(rawBody) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signatureHeader) );}See also
Section titled “See also”- Error Handling — Handling retries and non-2xx responses
- Environments & Testing — Setting up a local webhook test environment
- Rate Limits — Webhooks as an alternative to polling