standardwebhooks libraries verify deliveries out of the box, and the open spec defines the full scheme if you want to implement it yourself. Every delivery carries the three spec headers - Webhook-Id, Webhook-Timestamp, Webhook-Signature - shown in How a delivery looks.
Provision the secret once with
POST /api/notifications/signing-secret - it is returned a single time and never shown again. See Quickstart for provisioning and Secret rotation below for replacing it.Verify with a library
Use the officialstandardwebhooks package for your language. Each one takes the raw request body, the headers, and your whsec_ secret, and either returns the verified payload or throws.
whsec_ prefix, base64 decoding, constant-time comparison, multiple signatures, and timestamp tolerance for you.
Verify manually
If no official library fits your stack, implement the spec directly: recompute the signature and compare. A dependency-free reference implementation in Node’s built-incrypto:
verify.ts (Node crypto)
Verify against the raw body
The signature is computed over the exact bytes WalletSuite sent, so verification works on the raw request body - captured before any JSON parsing. (A parsed-and-re-serialized body is a different byte string: key order, whitespace, and number formatting all shift.) Capturing it is one route-level setting in every framework:Next.js App Router (route.ts)
Replay protection
A valid signature proves origin. Two checks keep deliveries fresh:- Timestamp window - reject deliveries whose
Webhook-Timestampis more than 5 minutes from your clock, in either direction. The timestamp is covered by the signature, so it is tamper-proof, and every retry is signed with a fresh timestamp - the window never rejects a legitimate delivery. - Deduplication - dedupe on
Webhook-Id: the same idempotency key you already use for retries covers replays. Implementation: Best Practices.
Test vector
Validate your verifier offline against a known-good vector before pointing real traffic at it.Standard Webhooks test vector
secret, headers, and body into your verifier - library or manual - and assert the verify call returns success. The vector’s timestamp is fixed in the past, so pin your clock to it (or widen the tolerance) for this test; a live timestamp check would otherwise reject it. Then flip one byte of the body and confirm verification now fails.
Manual implementations can additionally check the math directly: build the signed string id.timestamp.body, run HMAC-SHA256 + base64 with the decoded secret, and confirm it equals the v1, value shown.
Secret rotation
Rotate the signing secret whenever you suspect exposure, or on a routine schedule:404 SIGNING_SECRET_NOT_FOUND means no secret exists yet - provision one first with POST /api/notifications/signing-secret.
Next steps
Delivery & retries
Acknowledgement window, retry schedule, at-least-once semantics, and ordering guarantees.
Event payloads
The
transfer.received envelope, field semantics, and how to parse amounts and Tron addresses.Quickstart
Create a subscription, provision your signing secret, and receive your first event.
Best practices
Idempotency, fast acknowledgement, and hardening your receiver for production.