@usedelvaro/coupons
v0.1.1
Published
Verify and handle Delvaro coupon webhooks in any JavaScript/TypeScript store (Next.js on Vercel, Node, edge runtimes).
Maintainers
Readme
@usedelvaro/coupons
Receive Delvaro coupon webhooks in any JavaScript/TypeScript store and turn them into redeemable coupons in your own system — no plugin required.
When a shopper triggers a coupon (email send or form submit), Delvaro generates a
unique code and POSTs it to your endpoint, signed with HMAC-SHA256. This package
verifies the signature and gives you a typed payload. Works in Node, edge runtimes,
and Next.js App Router (uses the Web Crypto API, zero dependencies).
Install
npm install @usedelvaro/couponsQuick start (Next.js on Vercel)
// app/api/delvaro/coupons/route.ts
import {
createCouponWebhookHandler,
DuplicateCouponError,
} from "@usedelvaro/coupons";
export const POST = createCouponWebhookHandler({
secret: process.env.DELVARO_WEBHOOK_SECRET!,
async onCoupon({ code, discount_type, amount, expiry_date }) {
try {
await createCouponInYourStore({
code,
discount_type,
amount,
expiry_date,
});
} catch (err) {
// Tell Delvaro to retry with a fresh code on a collision.
if (isDuplicate(err)) throw new DuplicateCouponError();
throw err;
}
},
});Set DELVARO_WEBHOOK_SECRET to the signing secret shown when you register your
Custom store integration in the Delvaro dashboard, then paste the route's URL
(e.g. https://your-store.com/api/delvaro/coupons) into that integration.
Manual verification
If you don't want the handler wrapper, verify the signature yourself. Pass the raw request body (the signature is computed over the exact bytes).
import { verifyCouponWebhook } from "@usedelvaro/coupons";
const raw = await request.text();
const result = await verifyCouponWebhook(
raw,
request.headers.get("x-delvaro-signature"),
process.env.DELVARO_WEBHOOK_SECRET!,
);
if (!result.valid) {
return new Response(result.reason, { status: 401 });
}
const payload = JSON.parse(raw);Webhook contract
Delvaro sends:
POST {your_webhook_url}
Content-Type: application/json
X-Delvaro-Signature: t=<unix_ts>,v1=<hmac_sha256(`${t}.${rawBody}`, secret)>
{
"code": "ABCD-EFGH-JKLM",
"discount_type": "percent", // "percent" | "fixed"
"amount": 10,
"expiry_date": "2026-07-30T00:00:00.000Z", // or null
"email": "[email protected]",
"idempotency_key": "ws_123:ABCD-EFGH-JKLM",
"workspace_id": "ws_123"
}Respond with:
| Status | Meaning |
| ----------------------------------------- | --------------------------------------------------------- |
| 200 { "success": true, "code"?: "..." } | Coupon created. Return code to override Delvaro's code. |
| 409 | Code already exists — Delvaro retries with a new code. |
| any other non-2xx / timeout | Delvaro falls back to the block's static coupon. |
The signature uses a 5-minute timestamp tolerance by default to prevent replay.
API
createCouponWebhookHandler(options)→(request: Request) => Promise<Response>verifyCouponWebhook(rawBody, signatureHeader, secret, options?)→Promise<VerifyResult>DuplicateCouponError— throw fromonCouponto signal a 409- Types:
CouponWebhookPayload,VerifyOptions,VerifyResult,CouponWebhookHandlerOptions
License
MIT
