Skip to main content

Webhooks: hear about every change

Receive a signed POST every time the menu changes, instead of polling the API.

Instead of polling the API, register a URL and Delimenu will send it a POST every time the menu changes: when a product or a category is created, edited or deleted, and when the restaurant details change. Create them from Settings › Webhooks in the dashboard or with POST /restaurants/{ref}/webhooks, up to 5 per restaurant.

Available events: product.created, product.updated, product.deleted, category.created, category.updated, category.deleted, restaurant.updated, restaurant.deleted.

Verify the signature

Every request is signed in the Delimenu-Signature header with the endpoint secret, which is shown only once. Always verify it, against the body exactly as it arrived:

import { createHmac, timingSafeEqual } from 'node:crypto'

// rawBody: the request body exactly as received (a string or Buffer), not re-serialized JSON
export function verifyDelimenuWebhook(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(',').map(part => part.split('=')))
  const timestamp = Number(parts.t)
  if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > 300) return false

  const expected = createHmac('sha256', secret).update(`${timestamp}.${rawBody}`).digest('hex')
  const received = Buffer.from(parts.v1 ?? '', 'hex')
  return received.length === 32 && timingSafeEqual(received, Buffer.from(expected, 'hex'))
}

// const ok = verifyDelimenuWebhook(rawBody, req.headers['delimenu-signature'], process.env.DELIMENU_WEBHOOK_SECRET)

Retries

Answer with any 2xx in under 10 seconds and do the work afterwards. If it fails, we retry with increasing backoff up to 8 times over roughly a day, so use the event id to avoid processing it twice. An endpoint that exhausts its retries on 20 events in a row is disabled; you can enable it again from the dashboard.

Developers