Stage one: see the payload
Before writing a line of handler code, point the webhook at a request bin, a throwaway URL that captures whatever arrives (webhook.site and friends exist exactly for this). Fire a test event and read the actual payload: field names, types, timestamp format. Real payloads beat documentation every time.
Stages two and three: localhost, then trust
While building the handler, tunnel production events to your machine: an ngrok-style tunnel gives your localhost a public URL, so real events hit your debugger. Send yourself a message, watch delivered fire, force a bounce with a bad address, watch that fire too.
Before production, test the paranoid paths: replay the same event twice and confirm nothing double-processes, send a payload with a wrong signature and confirm your handler rejects it. Nitrosend signs every event with HMAC-SHA256; a handler that skips verification is an open door with logging.
Test against events, not API responses. I once trusted a live response that read "sent: 0, failed: 2, status: completed" and shipped the campaign again as a resend. It was the third copy. The response told me the request finished. Only the event stream tells you what actually happened.
Test data shapes what you can test, too. QA on one of our re-engagement flows surfaced a 404 on the unsubscribe link, and the cause was the test path itself: the legacy test-send used recipients that weren't real contacts, so there was no contact to bind an unsubscribe token to. The fix was routing test sends through the real transactional endpoint with real contacts, so every link works because nothing is mocked. If your test path and your production path differ, you're testing the test path.
Full parameters and responses live in the REST API docs and the API reference.
Go deeper
The signature check and the rest of the hardening: how to secure webhooks. The mechanism itself: webhooks explained.