Skip to main content

When to use

Use config: { public: true } when the caller can’t send X-Jelou-Token:
  • Webhooks from external services (Stripe, GitHub, Twilio)
  • Callbacks from payment gateways
  • Public APIs accessible from the browser

In define() mode

export default define({
  description: "Stripe webhook",
  input: z.object({ type: z.string(), data: z.object({ id: z.string() }) }),
  config: { public: true, methods: ["POST"], mcp: false },
  handler: async (input, ctx) => {
    ctx.log("Webhook received", { type: input.type });
    return { received: true };
  },
});

In app() mode — per-tool

export default app({
  tools: {
    webhook: define({
      config: { public: true, mcp: false },
      handler: async (input) => ({ ok: true }),
    }),
    admin: define({
      // protected by default — requires X-Jelou-Token
      handler: async (input) => ({ ok: true }),
    }),
  },
});

Override: app public, tool protected

export default app({
  config: { public: true },
  tools: {
    publicTool: define({ handler: async () => ({}) }),
    protectedTool: define({
      config: { public: false }, // override: requires token
      handler: async () => ({}),
    }),
  },
});

Security: validate webhooks

With public functions, the platform doesn’t validate anything. Your code is responsible:
handler: async (input, ctx, request) => {
  const signature = request.headers.get("x-webhook-signature");
  const secret = ctx.env.get("WEBHOOK_SECRET");

  const encoder = new TextEncoder();
  const key = await crypto.subtle.importKey(
    "raw", encoder.encode(secret),
    { name: "HMAC", hash: "SHA-256" }, false, ["verify"],
  );
  const body = await request.clone().text();
  const sigBytes = Uint8Array.from(atob(signature!), (c) => c.charCodeAt(0));
  const valid = await crypto.subtle.verify("HMAC", key, sigBytes, encoder.encode(body));

  if (!valid) return { error: "invalid_signature" };
  return { acknowledged: true };
}
Never trust a public function without validating the signature. Anyone can send requests to the URL.