Word of DishManage keys & webhooks →

API & Webhooks

A small REST API to mint Checks, read dishes and analytics, and receive events. Everything is tenant-scoped to your API key. Base URL: https://wordofdish.com/api/v1

Authentication

Create a key in Integrations. Keys are shown once. Send it as a bearer token:

Authorization: Bearer wod_live_xxxxxxxxxxxxxxxxxxxxxxxx

Endpoints

MethodPathScope
GET/api/v1/dishes?storeId={id}
List a store's dishes (use the ids when minting Checks).
read
GET/api/v1/checks?storeId={id}
List a store's Checks, newest first.
read
POST/api/v1/checks
Mint a Check. Consumes one credit; 402 when out of credits.
write
GET/api/v1/checks/{id}
Fetch a single Check by id.
read
GET/api/v1/analytics
Aggregate analytics for the tenant.
read

Mint a Check

curl -X POST https://wordofdish.com/api/v1/checks \
  -H "Authorization: Bearer wod_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "storeId": "store_123",
    "items": [{ "dishId": "dish_abc", "qty": 1 }],
    "locale": "en"
  }'

Returns 201 with the diner URL:

{
  "data": {
    "id": "chk_...",
    "shortId": "8bSilTS0",
    "status": "minted",
    "url": "https://wordofdish.com/r/8bSilTS0"
  }
}

Errors

Errors are JSON: { "error": "code" }.

Webhooks

Add an endpoint in Integrations and pick events. We POST JSON{ id, event, data } and retry up to 3× on non-2xx.

check.createdA Check was minted (owner app or API).
check.submittedA diner completed the survey for a Check.
feedback.positiveA submission scored positive (happy path).
feedback.negativeA submission scored negative (routed to recovery).
recovery.updatedA recovery case was created, replied to, or resolved.

Headers

Verify the signature

HMAC-SHA256 of the raw request body under your endpoint secret (whsec_…), hex-encoded. Compare in constant time.

import crypto from "node:crypto";

// Express example. Use the RAW body, not the parsed JSON.
app.post("/webhooks/wod", express.raw({ type: "application/json" }), (req, res) => {
  const sig = req.header("X-WoD-Signature") || "";            // "sha256=<hex>"
  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.WOD_WEBHOOK_SECRET)     // "whsec_..."
    .update(req.body)                                         // Buffer of the raw body
    .digest("hex");
  const ok = sig.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
  if (!ok) return res.status(401).end();
  const { event, data } = JSON.parse(req.body.toString());
  // handle event…
  res.status(200).end();
});

Python:

import hmac, hashlib

def verify(raw_body: bytes, header_sig: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header_sig)

No-code connectors

Prefer no code? Use our connectors for Zapier, Make, and n8n — authenticate with an API key, trigger on webhook events, and mint Checks as an action.

Zapier
Triggers + a Mint Check action
Make
Custom app blueprint
n8n
Community node package

Connector source + setup guides live in the connectors/ directory of the repo.