Webhooks you can trust: verify, de-duplicate, reconcile

Webhooks tell your server what happened on-chain. Three habits make them safe to build on: check the signature, de-duplicate by event id, and reconcile with the API.

The Valtu team

Webhooks are how Valtu tells your server that a deposit arrived or a payout confirmed. They're also an attack surface: anyone can send a request to your endpoint. Three habits make them safe to build on.

1. Check the signature

Every delivery is signed twice, over <timestamp>.<raw body>:

HeaderCheck it with
X-Valtu-Signature-Ed25519Your workspace's Ed25519 public key. Nothing secret to store. Recommended.
X-Valtu-SignatureHMAC-SHA256 with the endpoint's secret, shown once when you add the endpoint.

Verify either one, and reject anything signed more than 5 minutes ago. Verify against the raw body exactly as received: re-serialising the JSON first changes the bytes and breaks the check.

import { constructEvent } from "@valtu/wallet-kit";

const event = constructEvent(rawBody, req.headers, {
  publicKey: process.env.VALTU_WEBHOOK_PUBLIC_KEY,
});

2. De-duplicate, and don't rely on order

Delivery is at least once: if your endpoint doesn't answer with a 2xx within 10 seconds, the delivery is retried. So the same event can arrive more than once, and events can arrive out of order.

  • Store each event's id and skip ones you've already handled.
  • Act on the status in the event, not on the order events arrive in. A deposit.confirmed that arrives before deposit.pending is still confirmed.
  • Answer quickly, then do the slow work in the background.

3. Reconcile with the API

A webhook is a notification, not the record. Networks fail, deploys happen, endpoints go down. Run a regular catch-up:

GET /v1/deposits?after=2026-10-15T00:00:00Z
GET /v1/transfers?after=2026-10-15T00:00:00Z

Anything you missed is there. The dashboard also keeps every delivery attempt for 30 days, with your endpoint's response, and can resend one delivery or everything that was given up.

Putting it together

Verify, de-duplicate on id, credit on the status, and reconcile. Together they make the ledger correct even when the network between us isn't.

See webhooks in the API guide and the delivery guarantees.

Keep reading

More from the blog

developers · python The Valtu Python SDK is on PyPI pip install valtu: a signed API client, webhook verification and enclave attestation checks for Python 3.9 and later, with the same behavior as the TypeScript wallet kit. networks · developers One address, five networks: how EVM deposit addresses work With Valtu, a customer's 0x address is the same on Ethereum, BNB Chain, Polygon, Base and Lisk. Here is why that works, and what it means for deposits sent on any of them. payouts · developers Sending crypto payouts at scale: batches, approvals and limits Paying hundreds of sellers or employees in USDT is mostly an operations problem: never paying twice, getting the right people to approve, and keeping a wallet's queue moving.

Start with a test workspace today.

Same dashboard, same API, free test coins. Go live when your team is ready.