> ## Documentation Index
> Fetch the complete documentation index at: https://docs.genuka.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Verify Webhooks

> How to validate the authenticity of webhook events sent by Genuka.

# Verify Webhooks

When Genuka sends webhook events to your application, it is important to verify that the request is genuine and has not been tampered with.\
We achieve this by signing each webhook request with a secret key associated with your application.

***

## Signature Header

Every webhook request from Genuka includes a special header:

### X-Genuka-Signature

This header contains a hash signature generated with your **Webhook Secret** (provided when you create your application in the Genuka Developer Dashboard).

***

## Verification Process

1. Retrieve the raw request body exactly as received.
2. Compute a HMAC SHA256 hash using your Webhook Secret.
3. Compare your computed hash with the value in the `X-Genuka-Signature` header.
   * If they match → the request is authentic.
   * If not → discard the request.

***

## Example in Node.js (Next.js App Router)

```ts theme={null}
// app/api/webhook/route.ts
import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";

const WEBHOOK_SECRET = process.env.GENUKA_WEBHOOK_SECRET!;

function verifySignature(rawBody: string, signature: string): boolean {
  const computed = crypto
    .createHmac("sha256", WEBHOOK_SECRET)
    .update(rawBody, "utf8")
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(computed),
    Buffer.from(signature)
  );
}

export async function POST(req: NextRequest) {
  const signature = req.headers.get("x-genuka-signature");
  const rawBody = await req.text(); // must read as text for exact raw body

  if (!signature || !verifySignature(rawBody, signature)) {
    return NextResponse.json(
      { error: "Invalid signature" },
      { status: 401 }
    );
  }

  const event = JSON.parse(rawBody);

  switch (event.event) {
    case "order.created":
      console.log("✅ New order received:", event.data);
      break;
    case "order.completed":
      console.log("🎉 Order completed:", event.data);
      break;
    default:
      console.log("⚠️ Unhandled event:", event.event);
  }

  return NextResponse.json({ received: true }, { status: 200 });
}
```

| Error                | Cause                           | Solution                                                       |
| -------------------- | ------------------------------- | -------------------------------------------------------------- |
| `401 Unauthorized`   | Signature invalid or missing    | Ensure you are using the correct Webhook Secret                |
| `400 Bad Request`    | Malformed payload               | Check that your endpoint reads the raw request body properly   |
| Request not received | Server offline or URL incorrect | Verify your deployment and webhook URL in the Genuka dashboard |
