MODULE 05LESSON 04 · 11:10

Public APIs & Webhooks

Expose endpoints for external services to call.

SYSTEM_PLAYBACK_ACTIVEVideo placeholder
← PREVIOUSNEXT →

Sometimes you need to let the outside world call your app — a Stripe webhook, a Zapier trigger, a partner integration. Routes under /api/public/ skip authentication and are designed exactly for this.

/The non-negotiables

  • 01Verify signatures: Every webhook provider signs their payload. Verify with the shared secret before you trust a byte.
  • 02Validate input: Use a schema (Zod) to reject malformed payloads instead of crashing.
  • 03Return quickly: Do the minimum work needed and enqueue the rest — most providers time out at 10 seconds.
  • 04Never return PII: Public means public. Assume the response is scraped and logged.
ts
// Verify a webhook signature before processing
const signature = request.headers.get("x-webhook-signature");
const body = await request.text();

const expected = createHmac("sha256", process.env.WEBHOOK_SECRET!)
  .update(body)
  .digest("hex");

if (!signature || !timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
  return new Response("Invalid signature", { status: 401 });
}
Stable URLs for cron & webhooks

Use your project--<id>.lovable.app URL when configuring external services. It never changes, even if you rename the project.