mcpField
E
encore-webhook

encore-webhook

github.com/encoredevDevelopment30428 installsUpdated 2d ago
Repository

About encore-webhook

encore-webhook is a skill for building third-party webhook endpoints in Encore services. It explains raw-body access, signature verification, and quick acknowledgments followed by Pub/Sub processing.

Key features

  1. 01Receive webhooks with api.raw
  2. 02Read the unparsed request body
  3. 03Verify provider signatures
  4. 04Store signing secrets with secret(...)
  5. 05Respond quickly and hand work to Pub/Sub

Use cases

  1. 01Receive Stripe or GitHub webhooks
  2. 02Verify webhook payloads before processing
  3. 03Avoid delays from slow webhook handlers
  4. 04Queue verified events for asynchronous work

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/encoredev/skills --skill encore-webhook

After installing, type/encore-webhookin Claude Code to confirm it loaded.

Details

From the project README

Encore Webhook Endpoints

Instructions

Use api.raw(...) to receive inbound webhooks from third-party services. Raw endpoints give you direct access to the Node.js-style request and response objects, which you need for signature verification (the verification typically requires the unparsed raw body).

1. Import
import { api } from "encore.dev/api";
2. Define the endpoint with api.raw
export const stripeWebhook = api.raw(
  { expose: true, path: "/webhooks/stripe", method: "POST" },
  async (req, res) => {
    const sig = req.headers["stripe-signature"];
    // Read raw body
    const chunks: Buffer[] = [];
    for await (const chunk of req) chunks.push(chunk);
    const rawBody = Buffer.concat(chunks).toString("utf8");

    // Verify signature, parse event...

    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ received: true }));
  }
);
3. Verify the signature

Most providers sign webhooks. Read the secret with secret(...) from encore.dev/config (see the encore-secret skill) and verify before trusting the payload:

import { secret } from "encore.dev/config";
const stripeWebhookSecret = secret("StripeWebhookSecret");

// inside handler:
import Stripe from "stripe";
const stripe = new Stripe(stripeApiKey());
const event = stripe.webhooks.constructEvent(rawBody, sig, stripeWebhookSecret());

For GitHub, verify the HMAC-SHA256 in the X-Hub-Signature-256 header against the raw body using your webhook secret.

Common providers

ProviderSignature headerVerification
StripeStripe-Signaturestripe.webhooks.constructEvent(rawBody, sig, secret)
GitHubX-Hub-Signature-256HMAC-SHA256 over the raw body
SlackX-Slack-SignatureHMAC-SHA256 over v0:{timestamp}:{rawBody}
ShopifyX-Shopify-Hmac-Sha256HMAC-SHA256 (base64) over the raw body
TwilioX-Twilio-SignatureHMAC-SHA1 over URL + sorted form fields

Always respond quickly

Webhook senders retry on non-2xx or slow responses. Acknowledge with a 2xx as soon as the payload is verified, then enqueue the actual work via Pub/Sub (see encore-pubsub) instead of doing it in the request handler.

import { Topic } from "encore.dev/pubsub";

interface StripeEvent { id: string; type: string; data: unknown; }
const stripeEvents = new Topic<StripeEvent>("stripe-events", {
  deliveryGuarantee: "at-least-once",
});

// inside the raw handler, after verification:
await stripeEvents.publish({ id: event.id, type: event.type, data: event.data });
res.writeHead(200); res.end();

Guidelines

  • Use api.raw only for webhooks and other low-level HTTP integrations.
  • Always verify the provider's signature before trusting the payload.
  • Always respond 2xx fast — push slow work onto Pub/Sub.
  • Store the signing secret with secret(...); never inline it.
  • For typed JSON endpoints in your own service, use plain api(...) from the encore-api skill.

Comments

Markdown supported