// Receive + verify a CodeB webhook in Go (net/http). // Events include call.started, call.answered, call.ended, transcript.saved, // call.ice.connected, call.transferred, outbound-ai.finished, // sfu.publisher.connected, sfu.subscriber.connected. // European Digital Identity Wallet sign-in events flow through the same // dispatcher; verification is identical. // [webhooks-cookbook 2026-07-23] package main import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "io" "log" "net/http" "os" ) var secret = []byte(os.Getenv("CODEB_WEBHOOK_SECRET")) func handler(w http.ResponseWriter, r *http.Request) { raw, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "bad body", 400) return } got := r.Header.Get("X-CodeB-Signature") m := hmac.New(sha256.New, secret) m.Write(raw) want := "sha256=" + hex.EncodeToString(m.Sum(nil)) if len(got) != len(want) || !hmac.Equal([]byte(got), []byte(want)) { http.Error(w, "bad signature", 401) return } evt := r.Header.Get("X-CodeB-Event") delId := r.Header.Get("X-CodeB-Delivery-Id") log.Printf("[%s] %s %s", delId, evt, string(raw)) // ... process asynchronously; ACK within 5s. w.WriteHeader(200) w.Write([]byte("ok")) } func main() { http.HandleFunc("/webhook", handler) log.Fatal(http.ListenAndServe(":4000", nil)) }