Skip to main content
Every WalletSuite delivery is signed: an HMAC-SHA256 signature computed over the exact request with a per-account secret that only WalletSuite and you hold. A valid signature is cryptographic proof of origin and integrity - independent of network path or source IP. Verify the signature on every delivery, and reject anything that fails - before you read a single field from the body. WalletSuite implements Standard Webhooks exactly: the official 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 official standardwebhooks 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.
The library handles signed-string construction, the 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-in crypto:
verify.ts (Node crypto)
Never compare signatures with === or string equality. A naive comparison leaks timing information that can let an attacker recover a valid signature byte by byte. Always use a constant-time comparator such as crypto.timingSafeEqual (Node), hmac.compare_digest (Python), hmac.Equal (Go), or MessageDigest.isEqual (Java).

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-Timestamp is 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
Feed the 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:
The new secret is returned once. A 404 SIGNING_SECRET_NOT_FOUND means no secret exists yet - provision one first with POST /api/notifications/signing-secret.
Rotation is an immediate swap: every delivery signed after the call uses only the new secret, so deploy it to your receivers promptly.

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.