import type { Metadata } from "next"; export const metadata: Metadata = { title: "Webhook Docs — Epicure", }; export default function WebhookDocsPage() { return (
Learn how to integrate Epicure webhooks with your own tools, Zapier, and Make.
| Event | Description | Payload Fields |
|---|---|---|
| recipe.created | Fired when a recipe is created | id, title, authorId |
| recipe.updated | Fired when a recipe is updated | id, title, authorId |
| recipe.published | Fired when recipe visibility becomes public | id, title, authorId |
| recipe.deleted | Fired when a recipe is deleted | id, title |
| meal_plan.updated | Fired when a meal plan entry changes | weekStart, day, mealType |
| shopping_list.completed | Fired when shopping list marked complete | id, name |
| comment.added | Fired when a comment is added to your recipe | commentId, recipeId, recipeTitle |
Every webhook request is a POST with a JSON body in the following shape:
{`{
"event": "recipe.created",
"payload": { "id": "...", "title": "Pasta Carbonara", "authorId": "..." },
"timestamp": "2024-01-15T10:30:00.000Z"
}`}
Every request includes an{" "}
X-Epicure-Signature{" "}
header containing an HMAC-SHA256 digest of the raw request body, signed with your webhook
secret. Always verify this signature before processing the payload.
TypeScript / Node.js
{`import crypto from "crypto";
function verify(body: string, secret: string, signature: string): boolean {
const expected = crypto.createHmac("sha256", secret).update(body).digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}`}
Python
{`import hmac, hashlib
def verify(body: bytes, secret: str, signature: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)`}