Docs

Webhooks

Real-time events, cryptographically signed

When something changes in Valyd, we POST a signed event to your endpoint. Same envelope shape as Stripe. Same signing scheme. Same retry semantics.

Overview

  1. You register an endpoint URL in the dashboard or via API.
  2. Valyd assigns it a signing secret (whsec_…).
  3. When an event happens, Valyd POSTs a JSON payload with a Valyd-Signature header.
  4. Your handler verifies the signature, processes idempotently, returns 2xx.

If your endpoint returns non-2xx or times out, we retry with exponential backoff for 72 hours.

The event envelope

{
  "id": "evt_4f8a3b2c1d9e7f6a",
  "object": "event",
  "type": "identity.verified",
  "livemode": true,
  "created": 1746547200,
  "data": { "object": { "id": "vp_4f8a..." } }
}

Event types

Identity events

identity.createdA person completed onboarding.
identity.verifiedA live verification was performed and passed.
identity.verification_failedA live verification failed.

License events

license.addedA new credential was attached.
license.status_changedA license moved between active / suspended / expired.
license.expiring_soonFired 90, 30, and 7 days before expiry.

Agent events

agent.createdAn agent instance was minted.
agent.session_issuedA short-lived token was released to an agent.
approval.requestedAn agent created a human-in-the-loop approval.
approval.resolvedThe approver responded.

Signature verification

Verify the signature on every webhook. Without it, anyone who knows your URL can POST fake events.

import { Webhook } from "@valyd/node";

app.post("/webhooks/valyd", (req, res) => {
  const event = Webhook.verify(
    req.body, req.headers["valyd-signature"],
    process.env.VALYD_WEBHOOK_SECRET
  );
  res.json({ received: true });
});
Use the raw body

If your framework parses JSON before the verifier sees it, the signature will fail. Capture the raw body before any middleware.

Testing locally

$ valyd webhooks listen --forward-to localhost:3000/webhooks/valyd
 Listening on whsec_test_a8f2b3c4...
 Forwarding to http://localhost:3000/webhooks/valyd

$ valyd webhooks fire identity.verified
 Event evt_test_4f8a fired (200 OK)

Retries and replay

AttemptWait
2nd~30 seconds
3rd~2 minutes
4th~10 minutes
5th–nthExponential, capped at 12 hours
Final72 hours after first attempt — then dropped

Quick reference

POST/v1/webhooks/endpoints
GET/v1/webhooks/endpoints
POST/v1/webhooks/replay
DEL/v1/webhooks/endpoints/:id

Request API access →