Quick start
An E-Table237 administrator first creates your partner restaurant. The dashboard then displays your unique restaurant ID, webhook endpoint, and signing secret.
- Save the secret securely.It is used only by your backend and must never be exposed in browser code.
- Create the event payload.Include complete dish display details and the current aggregate rating.
- Sign the exact request body.Generate an HMAC-SHA256 signature using the timestamp and raw JSON body.
- POST the event.Send it over HTTPS and retry only when appropriate.
Explore Dishes ranks active dishes by average rating, then rating count, then dish name. A valid update can change the public order immediately.
Authentication
Every request needs two signature headers. The timestamp must be Unix time in seconds and within five minutes of the E-Table237 server clock.
| Header | Value |
|---|---|
X-ETable-Timestamp | Current Unix timestamp in seconds |
X-ETable-Signature | sha256=<hex-digest> |
Content-Type | application/json |
timestamp + "." + rawRequestBodyDigestHMAC_SHA256(restaurantSecret, signedValue)Sign the exact bytes sent in the HTTP body. Reformatting the JSON after calculating the signature causes verification to fail.
Rating update payload
The event upserts the dish record. This means your restaurant should send all required dish fields with every update—not only the rating.
{
"eventId": "rating-order-928-item-12",
"type": "dish.rating.updated",
"occurredAt": "2026-08-11T12:00:00.000Z",
"dish": {
"externalId": "menu-12",
"slug": "fish-grill",
"name": "Fish Grill",
"description": "Whole grilled fish with herbs and lemon.",
"category": "Grills",
"imageUrl": "https://restaurant.example/images/fish.jpg",
"imageAlt": "Whole grilled fish",
"price": 9500,
"currency": "XAF",
"isActive": true
},
"rating": {
"average": 4.8,
"count": 42
}
}| Field | Requirement |
|---|---|
eventId | Unique for this event. Reusing it returns a successful duplicate response without applying the update twice. |
occurredAt | ISO 8601 timestamp describing when the rating changed. |
dish.externalId | Your stable identifier for the dish. |
dish.slug | Lowercase URL slug using letters, numbers, and hyphens. |
dish.imageUrl | Public HTTPS image URL or an agreed E-Table237 asset path. |
rating.average | Number from 0 through 5. |
rating.count | Non-negative total number of ratings. |
Request examples
Node.js
import { createHmac } from "node:crypto";
const endpoint = "http://localhost:3000/api/webhooks/restaurants/{restaurantId}";
const secret = process.env.ETABLE237_WEBHOOK_SECRET;
const body = JSON.stringify(payload);
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = createHmac("sha256", secret)
.update(timestamp + "." + body)
.digest("hex");
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-ETable-Timestamp": timestamp,
"X-ETable-Signature": "sha256=" + signature,
},
body,
});
if (!response.ok) throw new Error(await response.text());cURL
Calculate the real signature in your application before sending this request.
curl -X POST "http://localhost:3000/api/webhooks/restaurants/{restaurantId}" \
-H "Content-Type: application/json" \
-H "X-ETable-Timestamp: 1770000000" \
-H "X-ETable-Signature: sha256=<hex-digest>" \
--data @rating-event.jsonResponses
| Status | Meaning | Action |
|---|---|---|
202 | New event accepted and applied | No retry |
200 | Event was already processed | No retry |
401 | Missing, expired, or invalid signature | Check secret, timestamp, and raw body |
404 | Restaurant is unknown or inactive | Contact E-Table237 |
422 | Payload validation failed | Correct the payload; do not retry unchanged |
500 | Temporary server failure | Retry with backoff |
{
"accepted": true,
"duplicate": false,
"dish": {
"id": "7b21…",
"slug": "fish-grill",
"rating": 4.8,
"ratingCount": 42
}
}Retries and idempotency
Retry network failures, timeouts, and 5xx responses with exponential backoff. Do not automatically retry authentication or validation failures.
- Keep the same
eventIdfor every retry of one event. - Generate a fresh timestamp and signature for each attempt.
- Suggested delays: 2 seconds, 10 seconds, 30 seconds, 2 minutes, then 10 minutes.
- Stop after a reasonable limit and alert your operations team.
Security and operations
- Store the webhook secret in a server-side secret manager.
- Never include the secret in a mobile app, browser bundle, repository, or log.
- Use HTTPS for dish images and webhook requests.
- Synchronize server clocks using NTP.
- Rotate the secret immediately if it may have been exposed.
- Keep event and response logs without recording the signing secret.
An E-Table237 administrator can rotate your restaurant secret. Rotation invalidates the previous secret immediately, so coordinate the change before production traffic continues.
Ready to connect your restaurant?
Contact the E-Table237 team for partner onboarding, webhook credentials, or help validating a test event.
Contact E-Table237