---
title: "Webhook Payload Schema Validation"
canonical: "https://test.abhinandan.one/go-webhook-schema-validation"
markdown_url: "https://test.abhinandan.one/go-webhook-schema-validation.md"
publisher: "Primitive SDKs"
kind: "reference"
content_type: "reference"
category: "Go SDK"
description: "ValidateEmailReceivedEvent and SafeValidateEmailReceivedEvent check a raw webhook payload against the embedded EmailReceivedEvent JSON Schema in the Go SDK."
keywords: ["ValidateEmailReceivedEvent", "SafeValidateEmailReceivedEvent", "EmailReceivedEvent JSON Schema", "email-received-event.schema.json Go", "WebhookValidationError Go", "embedded schema Go SDK"]
last_modified: "2026-08-11T18:54:57.066864+00:00"
published_at: "2026-08-11T18:54:56.907919+00:00"
sections:
  - {anchor: "validateemailreceivedevent", title: "ValidateEmailReceivedEvent"}
  - {anchor: "parsing-raw-bytes-first", title: "Parsing raw bytes first"}
  - {anchor: "where-the-schema-comes-from", title: "Where the schema comes from"}
  - {anchor: "relationship-to-unknown-event-types", title: "Relationship to unknown event types"}
  - {anchor: "next-steps", title: "Next steps"}
---

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

# Webhook Payload Schema Validation

Validate raw webhook payloads against the embedded EmailReceivedEvent JSON Schema in the Go SDK, using ValidateEmailReceivedEvent (error-raising) or SafeValidateEmailReceivedEvent (error-collecting).

The Go SDK embeds the canonical webhook JSON Schema (generated from `json-schema/email-received-event.schema.json` in the monorepo) and exposes `ValidateEmailReceivedEvent`, the function that checks an already-JSON-decoded webhook payload against it. It takes a decoded value (`map[string]any` or similar), not raw bytes.

Most callers never call it directly. `primitive.Receive(...)` and `primitive.HandleWebhook(...)` run this validation internally after signature verification; see [Receiving and Verifying Webhooks](https://test.abhinandan.one/go-receiving-webhooks.md). Reach for `ValidateEmailReceivedEvent` directly when you already have a parsed payload from somewhere else (a stored fixture, a replayed delivery, a test) and want the schema check without re-running signature verification.

## ValidateEmailReceivedEvent

`ValidateEmailReceivedEvent` validates a decoded payload against the embedded `email.received` schema and returns a typed `*EmailReceivedEvent` on success or an error on failure.

```go
package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"

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

func main() {
	raw, err := os.ReadFile("stored-delivery.json")
	if err != nil {
		log.Fatal(err)
	}

	var payload map[string]any
	if err := json.Unmarshal(raw, &payload); err != nil {
		log.Fatal(err)
	}

	event, err := primitive.ValidateEmailReceivedEvent(payload)
	if err != nil {
		log.Fatalf("invalid email.received payload: %v", err)
	}
	fmt.Println(event.Email.Headers.Subject)
}
```

| Aspect | Detail |
|---|---|
| Input | A decoded value (for example `map[string]any` from `json.Unmarshal`, or the result of `primitive.ParseJSONBody`) |
| Success return | `*EmailReceivedEvent`, `nil` |
| Failure return | `nil`, error |
| Used internally by | `primitive.HandleWebhook`, `primitive.Receive`, and `primitive.ParseWebhookEvent` (for the `email.received` case) |

See [Error Handling](https://test.abhinandan.one/go-error-handling.md) for the Go SDK's error types, including `WebhookValidationError`, `WebhookPayloadError`, and `WebhookVerificationError`.

## Parsing raw bytes first

`primitive.ParseJSONBody` turns a raw request body into the decoded value this validator expects, rejecting empty bodies, invalid UTF-8, and trailing content after the JSON value with a `WebhookPayloadError`. It also strips a leading UTF-8 BOM.

```go
parsed, err := primitive.ParseJSONBody(rawBody)
if err != nil {
	log.Fatal(err)
}

event, err := primitive.ValidateEmailReceivedEvent(parsed)
if err != nil {
	log.Fatal(err)
}
_ = event
```

## Where the schema comes from

The embedded schema is generated, not hand-maintained inside `sdk-go`. Its source of truth is `json-schema/email-received-event.schema.json` at the monorepo root, and changing the webhook contract means editing that file and running `make go-generate` from the repo root rather than editing anything under `sdk-go`. See [Monorepo Structure and Release Process](https://test.abhinandan.one/monorepo-and-releases.md) for the regeneration workflow and [Webhook Schema Codegen](https://test.abhinandan.one/webhook-schema-codegen.md) for how the schema compiles into per-language model and validator modules.

## Relationship to unknown event types

Strict schema validation applies only to `email.received`. `ParseWebhookEvent` routes `payment.*` bodies to a typed `PaymentEvent`, `interaction.*` bodies to `InteractionEvent`, and everything else to `UnknownEvent` for forward compatibility, so a future event type never fails validation. See [Webhook Event Types](https://test.abhinandan.one/go-webhook-event-types.md) for the full catalog and the `X-Webhook-Event` header discriminator.
