Skip to main content

Method

func (s *WebhooksSvcImpl) Verify(options *VerifyWebhookOptions) error

Parameters

options
*VerifyWebhookOptions
required
The webhook verification parameters
Payload
string
required
The raw webhook payload body as a string
Headers
WebhookHeaders
required
The webhook verification headers
Id
string
required
The svix-id header value
Timestamp
string
required
The svix-timestamp header value
Signature
string
required
The svix-signature header value
WebhookSecret
string
required
The signing secret from webhook creation (starts with whsec_)

Response

Returns nil if verification succeeds, or an error if verification fails.

Example

import (
    "io"
    "net/http"
    "github.com/resend/resend-go/v2"
)

func webhookHandler(w http.ResponseWriter, r *http.Request) {
    client := resend.NewClient("re_123456789")
    
    // Read the raw body
    body, err := io.ReadAll(r.Body)
    if err != nil {
        http.Error(w, "Failed to read body", http.StatusBadRequest)
        return
    }
    
    // Verify the webhook
    err = client.Webhooks.Verify(&resend.VerifyWebhookOptions{
        Payload: string(body),
        Headers: resend.WebhookHeaders{
            Id:        r.Header.Get("svix-id"),
            Timestamp: r.Header.Get("svix-timestamp"),
            Signature: r.Header.Get("svix-signature"),
        },
        WebhookSecret: "whsec_your_signing_secret",
    })
    
    if err != nil {
        http.Error(w, "Invalid signature", http.StatusUnauthorized)
        return
    }
    
    // Webhook is verified, process the event
    w.WriteHeader(http.StatusOK)
}

Notes

  • The verification implements HMAC-SHA256 signature validation
  • Timestamp validation prevents replay attacks (default tolerance: 5 minutes)
  • The signing secret is provided once when creating the webhook
  • All three headers (svix-id, svix-timestamp, svix-signature) are required

Build docs developers (and LLMs) love