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

# Handle a Webhook request

<CardGroup cols={2}>
  <Card title="Validate signature function" icon="code" href="/recipes/validate-signature" arrow="true">
    Take the validate signature snippet from our recipes, it'll be used below and it's important for security.
  </Card>

  <Card title="Create a Webhook endpoint" icon="webhook" href="https://dash.bitgpt.xyz/developers/webhooks" arrow="true">
    Use your dashboard to set up a webhook endpoint and receive real-time event notifications.
  </Card>
</CardGroup>

<CodeGroup dropdown>
  ```php Webhook.php wrap lines  theme={"system"}
  $rawBody = file_get_contents("php://input");
  $headers = getallheaders();
  $secret = 'your-webhook-secret';

  if (!validate_webhook($headers, $rawBody, $secret)) {
    http_response_code(400);
    echo json_encode(["error" => "Invalid signature"]);
    exit;
  }

  $event = $headers['X-Webhook-Event'] ?? '';
  $body = json_decode($rawBody, true);

  switch ($event) {
    case 'invoice.completed':
      // handleInvoiceCompleted($body);
      break;
    default:
      error_log("Unhandled event: $event");
      break;
  }

  http_response_code(200);
  echo "OK";
  ```

  ```javascript Webhook.js wrap lines  theme={"system"}
  const express = require('express');
  const bodyParser = require('body-parser');
  const app = express();
  const secret = process.env.WEBHOOK_SECRET;

  app.use(bodyParser.json());

  app.post('/webhook', (req, res) => {
    if (!validateWebhook(req, secret)) {
      return res.status(400).json({ error: "Invalid signature" });
    }

    const event = req.header("X-Webhook-Event");
    const body = req.body;

    switch (event) {
      case "invoice.completed":
        // handleInvoiceCompleted(body);
        break;
      default:
        console.warn("Unhandled event:", event);
    }

    res.sendStatus(200);
  });
  ```

  ```typescript Webhook.ts wrap lines  theme={"system"}
  import express, { Request, Response } from 'express';
  import { validateWebhook } from './validateWebhook'; // your function
  const app = express();
  const secret = process.env.WEBHOOK_SECRET as string;

  app.use(express.json());

  app.post("/webhook", (req: Request, res: Response) => {
    if (!validateWebhook(req.body, req.headers, secret)) {
      return res.status(400).json({ error: "Invalid signature" });
    }

    const event = req.headers["x-webhook-event"] as string;

    switch (event) {
      case "invoice.completed":
        // handleInvoiceCompleted(req.body);
        break;
      default:
        console.warn("Unhandled event:", event);
    }

    res.send("OK");
  });
  ```

  ```python Webhook.py wrap lines  theme={"system"}
  from flask import Flask, request, jsonify
  app = Flask(__name__)
  secret = "your-webhook-secret"

  @app.route("/webhook", methods=["POST"])
  def webhook():
    if not validate_webhook(request, secret):
      return jsonify({"error": "Invalid signature"}), 400

    event = request.headers.get("X-Webhook-Event")
    data = request.get_json()

    match event:
      case "invoice.completed":
        # handle_invoice_completed(data)
        pass
      case _:
        print(f"Unhandled event: {event}")

    return "OK", 200
  ```

  ```python Webhook.go wrap lines  theme={"system"}
  package main

  import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
  )

  func webhookHandler(w http.ResponseWriter, r *http.Request) {
    secret := "your-webhook-secret"

    if !validateWebhook(r, secret) {
      http.Error(w, "Invalid signature", http.StatusBadRequest)
      return
    }

    var body map[string]interface{}
    raw, _ := io.ReadAll(r.Body)
    json.Unmarshal(raw, &body)

    event := r.Header.Get("X-Webhook-Event")

    switch event {
    case "order:created":
      // handleOrderCreated(body)
    case "invoice.completed":
      // handleInvoiceCompleted(body)
    default:
      fmt.Printf("Unhandled event: %s\n", event)
    }

    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
  }
  ```

  ```java Webhook.java wrap lines  theme={"system"}
  import javax.servlet.http.*;
  import java.io.*;
  import java.util.Map;

  public class WebhookServlet extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
      String secret = "your-webhook-secret";
      Map<String, String> headers = extractHeaders(req); // implement as needed

      String body = new BufferedReader(new InputStreamReader(req.getInputStream()))
        .lines().reduce("", (acc, line) -> acc + line);

      ObjectMapper mapper = new ObjectMapper();
      Map<String, Object> bodyMap = mapper.readValue(body, Map.class);

      try {
        if (!WebhookValidator.validate(bodyMap, headers, secret)) {
          resp.setStatus(400);
          resp.getWriter().write("{\"error\":\"Invalid signature\"}");
          return;
        }

        String event = headers.get("X-Webhook-Event");

        switch (event) {
          case "invoice.completed":
            // handleInvoiceCompleted(bodyMap);
            break;
          default:
            System.out.println("Unhandled event: " + event);
        }

        resp.setStatus(200);
        resp.getWriter().write("OK");
      } catch (Exception e) {
        resp.setStatus(500);
        resp.getWriter().write("{\"error\":\"Internal server error\"}");
      }
    }
  }
  ```

  ```rust Webhook.rs wrap lines  theme={"system"}
  use actix_web::{post, web, HttpRequest, HttpResponse};
  use std::collections::HashMap;

  #[post("/webhook")]
  async fn webhook_handler(req: HttpRequest, body: String) -> HttpResponse {
    let secret = "your-webhook-secret";

    let headers = req
      .headers()
      .iter()
      .map(|(k, v)| (k.as_str().to_lowercase(), v.to_str().unwrap_or("").to_string()))
      .collect::<HashMap<String, String>>();

    let parsed: serde_json::Value = serde_json::from_str(&body).unwrap_or_default();

    if !validate_webhook(&parsed.as_object().unwrap(), &headers, secret) {
      return HttpResponse::BadRequest().json({ "error": "Invalid signature" });
    }

    let event = headers.get("x-webhook-event").unwrap_or(&"".to_string());

    match event.as_str() {
      "invoice.completed" => {
        // handle_invoice_completed(&parsed)
      }
      _ => {
        println!("Unhandled event: {}", event);
      }
    }

    HttpResponse::Ok().body("OK")
  }
  ```
</CodeGroup>
