---
title: "Standard Webhooks Signature Support (Go)"
canonical: "https://test.abhinandan.one/go-receiving-webhooks/go-standard-webhooks"
markdown_url: "https://test.abhinandan.one/go-receiving-webhooks/go-standard-webhooks.md"
publisher: "Primitive SDKs"
kind: "guide"
content_type: "reference"
category: "Go SDK"
parent: "go-receiving-webhooks"
description: "VerifyStandardWebhooksSignature checks the webhook-id, webhook-timestamp, and webhook-signature headers against a whsec_-prefixed secret in the Go SDK."
keywords: ["VerifyStandardWebhooksSignature", "Standard Webhooks Go", "webhook-id webhook-timestamp webhook-signature", "whsec_ secret Go SDK", "Primitive-Signature alternative"]
last_modified: "2026-08-11T18:55:02.190566+00:00"
published_at: "2026-08-11T18:55:01.984712+00:00"
sections:
  - {anchor: "when-to-use-this-instead-of-the-default", title: "When to use this instead of the default"}
  - {anchor: "prerequisites", title: "Prerequisites"}
  - {anchor: "verify-a-delivery", title: "Verify a delivery"}
  - {anchor: "step-extract-the-three-standard-webhooks-headers", title: "Extract the three Standard Webhooks headers"}
  - {anchor: "step-call-verifystandardwebhookssignature", title: "Call VerifyStandardWebhooksSignature"}
  - {anchor: "step-handle-a-verification-failure", title: "Handle a verification failure"}
  - {anchor: "timestamp-tolerance", title: "Timestamp tolerance"}
  - {anchor: "next-steps", title: "Next steps"}
---

> Documentation index: https://test.abhinandan.one/llms.txt

# Standard Webhooks Signature Support (Go)

Verify Primitive webhook deliveries using the Standard Webhooks header format instead of the default Primitive-Signature HMAC scheme, using VerifyStandardWebhooksSignature in the Go SDK.

Use `VerifyStandardWebhooksSignature` when a receiver already expects the [Standard Webhooks](https://www.standardwebhooks.com/) convention (`webhook-id` / `webhook-timestamp` / `webhook-signature` headers, `whsec_`-prefixed secret) instead of Primitive's own `Primitive-Signature` header. Reach for it only when your tooling is already wired for that convention; every other Go SDK integration should verify with the default HMAC scheme documented in [Receiving and Verifying Webhooks](https://test.abhinandan.one/go-receiving-webhooks.md).

Both schemes sign the exact same raw request body, so the trust guarantee is identical.

## When to use this instead of the default

Use Standard Webhooks only when a receiver, gateway, or shared verification library in your stack already speaks the `webhook-id` / `webhook-timestamp` / `webhook-signature` convention. Otherwise use Primitive's default `Primitive-Signature: t=<unix-seconds>,v1=<hex>` header, verified automatically by `primitive.Receive` and `primitive.HandleWebhook`, which needs no extra secret formatting.

## Prerequisites

- The Go SDK installed: `go get github.com/primitivedotdev/sdks/sdk-go@latest`
- Your webhook secret from `GET /account/webhook-secret`, in its `whsec_`-prefixed form
- The raw, unparsed request body and its `webhook-id`, `webhook-timestamp`, and `webhook-signature` headers

> **Warning:** Verify against the exact raw request body bytes, before any JSON decoding or re-serialization. Re-serializing the body (even reformatting whitespace) changes the bytes the signature was computed over and verification will fail.

## Verify a delivery

`VerifyStandardWebhooksSignature` takes a `StandardWebhooksVerifyOptions` struct with the raw body, the three header values, and your secret, and returns `(bool, error)`. Deliveries older than the 300-second (5-minute) default tolerance, or more than 60 seconds in the future, are rejected.

### 1. Extract the three Standard Webhooks headers

Pull `webhook-id`, `webhook-timestamp`, and `webhook-signature` from the incoming request. Header names are case-insensitive per RFC 7230; match them accordingly.

### 2. Call VerifyStandardWebhooksSignature

Pass the raw body, the three header values, and your `whsec_`-prefixed secret:

```go
package main

import (
	"fmt"
	"log"
	"net/http"

	primitive "github.com/primitivedotdev/sdks/sdk-go"
)

func handle(w http.ResponseWriter, r *http.Request, rawBody []byte) {
	ok, err := primitive.VerifyStandardWebhooksSignature(primitive.StandardWebhooksVerifyOptions{
		RawBody:         rawBody,
		MsgID:           r.Header.Get("webhook-id"),
		Timestamp:       r.Header.Get("webhook-timestamp"),
		SignatureHeader: r.Header.Get("webhook-signature"),
		Secret:          "whsec_...",
	})
	if err != nil {
		log.Printf("invalid webhook signature: %v", err)
		http.Error(w, "invalid signature", http.StatusBadRequest)
		return
	}
	if !ok {
		http.Error(w, "invalid signature", http.StatusBadRequest)
		return
	}

	fmt.Fprintln(w, "verified")
}
```

### 3. Handle a verification failure

`VerifyStandardWebhooksSignature` returns a non-nil error on a malformed header, an expired timestamp, or a signature mismatch. Respond with a 4xx status and do not process the payload; a genuine delivery from Primitive is redelivered on a 5xx or timeout, not on a 4xx rejection of a bad signature.

## Timestamp tolerance

The default tolerance rejects any delivery whose `webhook-timestamp` is more than 300 seconds (5 minutes) older than your wall clock, or more than 60 seconds in the future, which defends against replayed captures of old but otherwise-valid signatures. Set `ToleranceSeconds` on `StandardWebhooksVerifyOptions` to change the past-age window.
