Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

To receive PDF-generation webhooks safely in Go, expose an HTTPS POST endpoint, limit and read the request body once, verify the provider’s signature against those exact raw bytes, then parse and validate the event. Record its ID with a uniqueness constraint, enqueue PDF retrieval and other work, and return a successful 2xx response promptly. Do not download or process the PDF inside the request handler: providers may retry slow or unsuccessful deliveries, so your design must tolerate duplicates.

What a reliable webhook handler must do

A webhook is an HTTP request sent by a provider when an asynchronous job reaches an event such as PDF-generation success or failure. Your endpoint is responsible for authenticating the delivery, accepting it durably, and handing the potentially slow work to a background worker.

  1. Accept only the expected HTTP method on an HTTPS endpoint.
  2. Limit the body before reading it and preserve the exact bytes for signature verification.
  3. Verify the signature using the provider’s documented algorithm, secret, headers, and timestamp rules.
  4. Parse the authenticated payload and validate its event type and identifiers.
  5. Persist the provider’s event or webhook ID as an idempotency key.
  6. Queue PDF retrieval and downstream work, then acknowledge the delivery with a 2xx response.

These steps are deliberately ordered. Parsing and reserializing JSON before signature verification can change whitespace, escaping, or field ordering, causing valid signatures to fail—or leading an implementation to verify something other than what the provider sent.

Implement the Go endpoint

The following standard-library example shows a complete HTTP handler and a deliberately illustrative HMAC verifier. The verifier expects an X-Example-Signature header containing a hex-encoded HMAC-SHA256 of the raw body. That header and format are an example for a service you control, not a universal PDF-webhook convention. Replace the verifier with the exact scheme documented by your provider; do not assume providers use this header, algorithm, timestamp format, or signing input.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
#1 Best Overall
Elebase USB to USB C Adapter for iPhone 18 Pro Max,USBC Car Charger Adapter
  • Read Before You Buy — No Video Output: These adapters support charging and USB 2.0 data transfer, but cannot transmit video signals. Except for standard USB webcams (which use USB data only), they are not compatible with HDMI/DisplayPort cables, video-capable USB-C hubs, or docking stations with video output.
  • Convert USB-A Ports to USB-C: Designed to connect USB-C earphones, cables, flash drives, card readers, and other USB-C accessories to standard USB-A ports. Plug-and-play with no drivers or software required.
  • Aluminum Alloy Housing: Built with a sturdy aluminum alloy shell that aids in heat dissipation and protects against daily wear and scratches. Designed to maintain a stable and secure connection.
  • Compact & Travel-Friendly: The ultra-compact design allows the adapter to stay plugged into your device without blocking adjacent ports or adding bulk, reducing wear and tear on your original USB ports.
  • 12-Month Warranty: Backed by a 12-month manufacturer warranty for peace of mind. Designed to meet strict quality control standards for reliable everyday performance.
package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"errors"
	"io"
	"log"
	"net/http"
	"os"
	"strings"
	"sync"
	"time"
)

type Event struct {
	ID          string `json:"id"`
	Type        string `json:"type"`
	JobID       string `json:"job_id"`
	DownloadURL string `json:"download_url"`
	FailureCause string `json:"failure_cause"`
}

type Store interface {
	// InsertIfNew must persist ID atomically and return false if it already exists.
	InsertIfNew(id string) (bool, error)
}

type Queue interface {
	Enqueue(event Event) error
}

type Handler struct {
	Secret string
	Store  Store
	Queue  Queue
}

func verifyExampleHMAC(raw []byte, secret, header string) error {
	if secret == "" || header == "" {
		return errors.New("missing secret or signature")
	}
	got, err := hex.DecodeString(strings.TrimSpace(header))
	if err != nil {
		return errors.New("signature is not valid hex")
	}
	mac := hmac.New(sha256.New, []byte(secret))
	_, _ = mac.Write(raw)
	if !hmac.Equal(got, mac.Sum(nil)) {
		return errors.New("signature mismatch")
	}
	return nil
}

func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
		return
	}
	// Cap memory and reject oversized bodies; 1 MiB is the limit used in
	// the OpenAI Go SDK example, not a universal provider requirement.
	r.Body = http.MaxBytesReader(w, r.Body, 1<<20)
	defer r.Body.Close()
	raw, err := io.ReadAll(r.Body)
	if err != nil {
		var maxErr *http.MaxBytesError
		if errors.As(err, &maxErr) {
			http.Error(w, "request body too large", http.StatusRequestEntityTooLarge)
		} else {
			http.Error(w, "could not read request body", http.StatusBadRequest)
		}
		return
	}
	if err := verifyExampleHMAC(raw, h.Secret, r.Header.Get("X-Example-Signature")); err != nil {
		log.Printf("webhook rejected: signature verification failed")
		http.Error(w, "invalid signature", http.StatusBadRequest)
		return
	}
	var event Event
	if err := json.Unmarshal(raw, &event); err != nil {
		http.Error(w, "invalid JSON", http.StatusBadRequest)
		return
	}
	if event.ID == "" || event.Type == "" || event.JobID == "" {
		http.Error(w, "missing event fields", http.StatusBadRequest)
		return
	}
	switch event.Type {
	case "documents.generation.success":
		if event.DownloadURL == "" {
			http.Error(w, "missing download URL", http.StatusBadRequest)
			return
		}
	case "documents.generation.failure":
		if event.FailureCause == "" {
			http.Error(w, "missing failure cause", http.StatusBadRequest)
			return
		}
	default:
		// Decide whether unknown event types should be ignored or rejected
		// according to the provider's delivery and retry behavior.
		http.Error(w, "unsupported event type", http.StatusBadRequest)
		return
	}
	inserted, err := h.Store.InsertIfNew(event.ID)
	if err != nil {
		log.Printf("webhook persistence failed: %v", err)
		http.Error(w, "temporary persistence failure", http.StatusServiceUnavailable)
		return
	}
	if !inserted {
		// A duplicate already accepted: acknowledge without repeating work.
		w.WriteHeader(http.StatusOK)
		return
	}
	if err := h.Queue.Enqueue(event); err != nil {
		// Production systems should make recording the event and enqueuing
		// work atomic (for example, with a transactional outbox).
		log.Printf("webhook enqueue failed for event %s: %v", event.ID, err)
		http.Error(w, "temporary queue failure", http.StatusServiceUnavailable)
		return
	}
	w.WriteHeader(http.StatusOK)
}

// Replace these in-memory examples with durable implementations.
type MemoryStore struct { mu sync.Mutex; seen map[string]bool }
func (s *MemoryStore) InsertIfNew(id string) (bool, error) {
	s.mu.Lock(); defer s.mu.Unlock()
	if s.seen[id] { return false, nil }
	s.seen[id] = true
	return true, nil
}
type LogQueue struct{}
func (LogQueue) Enqueue(e Event) error { log.Printf("queued event=%s type=%s job=%s", e.ID, e.Type, e.JobID); return nil }

func main() {
	secret := os.Getenv("PDF_WEBHOOK_SECRET")
	if secret == "" { log.Fatal("set PDF_WEBHOOK_SECRET") }
	store := &MemoryStore{seen: make(map[string]bool)}	handler := Handler{Secret: secret, Store: store, Queue: LogQueue{}}
	server := &http.Server{
		Addr: ":8080", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			if r.URL.Path != "/webhooks/pdf" { http.NotFound(w, r); return }
			handler.ServeHTTP(w, r)
		}),
		ReadHeaderTimeout: 5 * time.Second,
		ReadTimeout: 15 * time.Second,
		WriteTimeout: 15 * time.Second,
		IdleTimeout: 60 * time.Second,
	}
	log.Fatal(server.ListenAndServe()) // Terminate TLS at a trusted HTTPS proxy in production.
}

Save this as main.go and run PDF_WEBHOOK_SECRET='replace-with-a-secret' go run main.go. It listens on port 8080 at /webhooks/pdf. The in-memory store and logging queue make the example self-contained, but they do not survive restarts, coordinate across replicas, or perform PDF downloads. In production, put durable storage and a durable queue behind the interfaces. The OpenAI Go SDK repository’s example uses a 1 MiB maximum body and configures read, write, header, and idle timeouts; use that as a concrete starting point, then choose limits that fit the provider’s payloads and your infrastructure: OpenAI Go SDK.

Make accepting and queuing work durable

The example inserts the event ID before enqueueing. If the process crashes after the insert but before the queue write, a redelivery can look like a duplicate even though no job was queued. Avoid that failure window by using a database transaction that stores the event and an outbox row together; a separate dispatcher publishes outbox rows to the queue and marks them sent. Alternatively, use a queue or database operation that provides an equivalent atomic handoff.

Enforce uniqueness in persistent storage, such as a unique index on the provider event ID. An in-memory map is only suitable for demonstrating the handler. If a provider’s webhook ID is the recommended delivery-level key, use that; otherwise use its documented event ID. Do not invent a key from a PDF URL if distinct events for the same job may legitimately occur.

Rank #2
Anker USB-C Hub, 5-in-1 USB Hub for Laptops, 4K HDMI Multiport Adapter
  • 5-in-1 USB-C Hub: Experience comprehensive connectivity featuring a Power Delivery input, two USB-A 2.0 ports, a USB-A 3.0 port, and an HDMI port. (Note: The USB-C power delivery input port is only for connecting an external wall charger to power your laptop and cannot power peripheral devices.)
  • 90W Pass-Through Charging: Achieve optimal charging with 90W pass-through power to your laptop, supported by a total input of 100W, with the hub reserving 10W for operational efficiency. (Note: Wall charger not included.)
  • Quick Data Transfers: Accelerate your productivity with rapid data transfers using a high-speed 5Gbps USB 3.0 port and two 480Mbps USB 2.0 ports.
  • 4K HDMI Display: Enhance your visual experience with a hub capable of delivering 4K resolution at 30Hz in both mirror and extend modes. Please note that this hub is compatible with MacBook (macOS 12 and newer), Windows 10 and 11, ChromeOS, and laptops equipped with DP Alt Mode and Power Delivery. Note: This device is not compatible with Linux.
  • What You Get: Anker USB-C Hub (5-in-1, 4K HDMI), welcome guide, 18-month warranty, and our friendly customer service.

Should the handler download the PDF before returning 200?

Usually, no. A PDF download, object-storage upload, OCR pass, or notification can take longer than the provider’s request deadline and cause redelivery. Acknowledge once the authenticated event has been durably recorded and work is safely queued; let a worker fetch the PDF and retry transient download or storage failures independently.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Whether to return 2xx before or after queueing depends on your durability design. Returning 2xx after only placing work in an in-memory channel risks losing accepted jobs on a crash. Returning 2xx after a durable queue write or committed outbox record is safer. If persistence or enqueueing fails, return a retryable non-2xx response rather than acknowledging work you have lost.

PDF links should be treated as provider-controlled input. In the worker, use the provider’s documented URL behavior, validate destinations and redirects to reduce server-side request forgery risk, set connection and total timeouts, cap the downloaded size, and avoid logging signed URLs or credentials. The specific URL lifetime and access requirements are provider-specific and should be confirmed in its documentation.

Rank #3
Sale
Anker USB C Hub, 7in1 Multi-Port USB Adapter, 4K@60Hz USBC to HDMI Splitter
  • Sleek 7-in-1 USB-C Hub: Features an HDMI port, two USB-A 3.0 ports, and a USB-C data port, each providing 5Gbps transfer speeds. It also includes a USB-C PD input port for charging up to 100W and dual SD and TF card slots, all in a compact design.
  • Flawless 4K@60Hz Video with HDMI: Delivers exceptional clarity and smoothness with its 4K@60Hz HDMI port, making it ideal for high-definition presentations and entertainment. (Note: Only the HDMI port supports video projection; the USB-C port is for data transfer only.)
  • Double Up on Efficiency: The two USB-A 3.0 ports and a USB-C port support a fast 5Gbps data rate, significantly boosting your transfer speeds and improving productivity.
  • Fast and Reliable 85W Charging: Offers high-capacity, speedy charging for laptops up to 85W, so you spend less time tethered to an outlet and more time being productive.
  • What You Get: Anker USB-C Hub (7-in-1), welcome guide, 18-month warranty, and our friendly customer service.

Retries, duplicate delivery, and fast acknowledgements

OpenAI’s webhook guidance says endpoints should respond quickly with a successful 2xx status to acknowledge receipt: OpenAI Webhooks. It also states that if the endpoint does not return 2xx or does not respond within a few seconds, delivery is retried for up to 72 hours with exponential backoff. The same guide notes that duplicate copies can occur and that the webhook-id header can be used as an idempotency key. Those are OpenAI-specific documented behaviors, not guarantees for every PDF service.

For each provider, check the current retry window, timeout, signature scheme, event identifier, and replay behavior. Your endpoint should be safe if the same delivery arrives multiple times, and your worker should also be safe if a queued job runs more than once. Make downstream operations idempotent too—for example, use a stable job ID for the final PDF record and make storage writes deterministic.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose the provider-specific event and job flow

PDFMonkey

PDFMonkey documents documents.generation.success, which includes an available download_url, and documents.generation.failure, which supplies a failure_cause. Its webhook documentation describes automatic retries and signature verification and was last updated September 24, 2026: PDFMonkey webhook documentation. Use its documented signature procedure rather than the example HMAC header above. On success, queue retrieval of the download URL; on failure, record the cause and route the job to your failure handling path.

Rank #4
Sale
UGREEN USB to USB C Adapter Combo 4-Pack, 10Gbps USB C Converter Space Gray
  • Dual Converters, Infinite Potential:Includes 2× USB C male to USB A female adapters and 2× USB A male to USB C female adapters. Perfect for a wide range of uses—tablets with Bluetooth keyboards, expand USB ports on macbook, and more. Two different converters for all your daily needs
  • Next-Level 10Gbps & 3A Charging: No more slow 480Mbps, this usb to usb c adapter has a transfer speed of up to 10Gbps, allowing you to do more transferring in less time. This usb adapter fits both USB A and USB C charger, supporting up to 3A fast charging
  • Upgraded Exquisite Craftsmanship: With an aluminum alloy housing and metal connector, the usbc to usb adapter is extremely durable and sturdy. Rigorously tested to withstand more than 10,000 times of plugging and unplugging, ensuring long-lasting performance
  • Broad Compatible: The usb c to usb adapter widely supports all USB C/ USB A devices like laptops, tablets, cellphones, car chargers, and phone chargers. Such as compatible with MacBook Pro/Air 2023/2022, Thunderbolt 4/3 Devices,Apple MagSafe Watch 9/8/7/SE/Ultra, iPad Pro 2022/2021, Samsung Galaxy S23/S20/S10, and iPhone 17/16/15 Pro. Plug and play
  • Please Note: To reach 10Gbps speed, keep the cable under 3.3 ft. For USB A Male to USB C adapters, try flipping the USB C connector. USB C Male to USB A adapters support bidirectional 10Gbps transfer within 3.3 ft

PDF Generator API

PDF Generator API documents POST /documents/generate/async for asynchronous generation and GET /documents/async/{jobId} for status retrieval. Its Go client documentation describes JWT authentication, limits of 2 requests per second and 60 requests per minute, and API version 4.0.28: PDF Generator API Go client. Those limits and version are from its 2026 documentation and can change; account for them when scheduling generation and polling, and verify the current provider documentation before deployment. A webhook can notify your system, while the status endpoint can help reconcile a missed notification or diagnose a job.

Questions to compare before choosing a provider

  • What signature scheme, headers, timestamp checks, and official SDK helpers are supported?
  • What event types and identifiers are sent, and how is a generated PDF retrieved?
  • How long and how often are failed deliveries retried? Is there a replay tool?
  • Is there an asynchronous job-status endpoint to reconcile missing webhooks?
  • What rate limits, regional processing options, and observability tools apply?

Production hardening and observability

  • Transport: serve the endpoint over HTTPS, either directly or through a trusted TLS-terminating proxy. Restrict access to the intended route and method.
  • Resource limits: set a body-size limit, read-header timeout, read timeout, write timeout, and idle timeout. Tune these against the provider’s request size and delivery deadline.
  • Signature checks: compare MACs in constant time where applicable. If the provider signs a timestamp, enforce its documented tolerance and include the timestamp in verification exactly as specified.
  • Schema checks: validate event ID, type, job/document ID, and fields required for that event. Decide deliberately how to handle unknown event types, especially when rejecting them might trigger repeated delivery.
  • Secrets: store webhook secrets outside source control, rotate them according to provider support, and never log them or full authorization-bearing payloads.
  • Metrics and logs: record counts for accepted, rejected, duplicate, persistence-failed, and queue-failed events. Include a correlation/event ID, but redact secrets and signed download URLs.
  • Reconciliation: where a provider offers job status lookup, periodically reconcile long-running jobs or missing terminal events rather than relying exclusively on delivery.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Troubleshooting common failures

Valid deliveries fail signature verification

Check that verification uses the original raw bytes, not parsed and re-encoded JSON. Confirm the secret, header spelling, encoding, algorithm, timestamp handling, and exact signed message format against that provider’s documentation. A generic HMAC example will not work unless the provider actually specifies that scheme.

The provider keeps retrying after an apparent success

Inspect the actual HTTP response status and time-to-response at the public endpoint, including reverse-proxy behavior. A redirect, proxy timeout, or a response emitted only after a slow PDF download may not count as a successful acknowledgement. Ensure the handler returns a 2xx only after durable acceptance.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Best Value
Anker USB C Hub, 5-in-1 USBC to HDMI Splitter with 4K Display
  • 5-in-1 Connectivity: Equipped with a 4K HDMI port, a 5 Gbps USB-C data port, two 5 Gbps USB-A ports, and a USB C 100W PD-IN port. Note: The USB C 100W PD-IN port supports only charging and does not support data transfer devices such as headphones or speakers.
  • Powerful Pass-Through Charging: Supports up to 85W pass-through charging so you can power up your laptop while you use the hub. Note: Pass-through charging requires a charger (not included). Note: To achieve full power for iPad, we recommend using a 45W wall charger.
  • Transfer Files in Seconds: Move files to and from your laptop at speeds of up to 5 Gbps via the USB-C and USB-A data ports. Note: The USB C 5Gbps Data port does not support video output.
  • HD Display: Connect to the HDMI port to stream or mirror content to an external monitor in resolutions of up to 4K@30Hz. Note: The USB-C ports do not support video output.
  • What You Get: Anker 332 USB-C Hub (5-in-1), welcome guide, our worry-free 18-month warranty, and friendly customer service.

The same PDF is processed more than once

Check that event IDs have a persistent unique constraint shared by all application instances, and that the worker’s business operations are also idempotent. A process-local map cannot prevent duplicates across restarts or replicas.

Large payloads return 413 or fail while reading

The request exceeded the configured body limit or was interrupted. Compare the limit with the provider’s documented maximum payload and your proxy’s limit. Raise it only as needed, keeping a bounded limit in both application and proxy layers.

Webhook accepted but no PDF appears

Trace the event ID from handler logs to the durable event/outbox, queue, worker, download, and storage result. Check worker permissions, URL expiry rules, network access, provider rate limits, and retry/dead-letter handling. For generation services with a status API, query the job separately to distinguish a failed generation from a lost delivery.

Test locally and deploy safely

  1. Run the handler behind a public HTTPS tunnel or in a cloud development environment. OpenAI’s webhook guide names ngrok and cloud development environments as ways to make a local endpoint publicly reachable: OpenAI Webhooks.
  2. Use the provider’s test-event or webhook tooling when available; send both success and failure payloads and confirm signature verification.
  3. Send the same event twice and verify that only one durable work item is created.
  4. Simulate queue or database failure and confirm that the endpoint does not falsely acknowledge lost work.
  5. Test malformed JSON, missing required fields, invalid signatures, and oversized bodies.
  6. Deploy with production TLS, durable idempotency storage, a durable queue or transactional outbox, bounded worker retries, and redacted structured observability.

Or skip the browser setup

If your workflow also needs clean website screenshots or PDF captures, ScreenshotNeo is a screenshot API and MCP server; it is not a replacement for a PDF-generation webhook. A single GET request can capture a page as PNG, JPEG, WebP, or PDF:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Cookie banners are accepted and removed before capture, alongside known newsletter popups and chat widgets; these cleanup steps can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers indicate the page verdict and billing status. Its MCP server offers take_screenshot, get_page_info, and capture_pdf for AI agents using Claude, Cursor, or another MCP client. The Free plan includes 1,000 shots per month without a card; paid plans start at $5 for 3,000 shots. Sign up free for 1,000 screenshots a month with no card.

Frequently Asked Questions

Can I use the same signature-verification code for every PDF webhook provider?

No. Use each provider’s documented signing scheme, headers, secret, and timestamp rules. The HMAC format in the example is explicitly illustrative.

Does a webhook replace a PDF provider’s job-status API?

Not necessarily. A status endpoint can help reconcile jobs when a notification is delayed or missed; PDF Generator API documents an asynchronous job lookup endpoint.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.