Zapier
A Zap that pulls today's list into a task, and one that receives a late delivery.
Webhooks by Zapier
Choose Webhooks by Zapier, then GET. URL https://app.refilloapp.com/api/v1/needs-you. Headers: Authorization, Bearer and the key. Store the key in a Zapier secret. The data items are the rows to send on to your task app. Map title, deadline and action_label. Do not map money into a price field: the sentence already says what the money is.
Catch a hook
For a late delivery, use Catch Hook and put that URL on a Refillo endpoint subscribed to A delivery is late. The first Code step verifies Refillo-Signature with the Node function. A failed check stops the Zap. The payload's data.purchase_order_id is the delivery to open.
The check
Same Node function as the webhooks guide.
import { createHmac, timingSafeEqual } from "node:crypto";
/** The check the webhooks guide shows. Same rule as Refillo's own verifier. */
export function verifyWebhook(secret: string, header: string, rawBody: string, nowSeconds: number): boolean {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
const t = Number(parts.t);
if (!Number.isInteger(t) || Math.abs(nowSeconds - t) > 300) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
const given = Buffer.from(parts.v1 ?? "", "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
}
if (process.argv[1]?.endsWith("verify-webhook.ts")) {
const secret = "whsec_example";
const body = '{"id":"1"}';
const t = 1_700_000_000;
const mac = createHmac("sha256", secret).update(`${t}.${body}`).digest("hex");
if (!verifyWebhook(secret, `t=${t},v1=${mac}`, body, t)) throw new Error("expected a valid signature");
if (verifyWebhook(secret, `t=${t},v1=${mac}`, "other", t)) throw new Error("expected a mismatch");
console.log("verify_webhook ok");
}