Skip to main content
Webhooks let your application receive automatic notifications when events happen in your Truthlocks account — for example, when an attestation is minted, a key is rotated, or a verification fails. Instead of polling the API for changes, your server receives an HTTP POST request with the event details.

How it works

1

Register an endpoint

Add a webhook endpoint in Settings > Webhooks in the tenant console. Provide a publicly reachable HTTPS URL and choose which event types you want to receive.
2

Receive events

When a matching event occurs, Truthlocks sends an HTTP POST request to your URL with a JSON payload describing the event.
3

Verify the signature

Each request includes an HMAC-SHA256 signature in the X-Truthlocks-Signature header. Verify it using the endpoint secret to confirm the request came from Truthlocks.
4

Respond with 200

Return an HTTP 200 status code to acknowledge receipt. If your endpoint fails or times out, Truthlocks retries with exponential backoff.

Event types

Events are grouped into categories. You can subscribe to individual events or use a wildcard (attestation.*) to receive all events in a category.
CategoryEventTrigger
Attestationsattestation.createdA new attestation is minted
attestation.revokedAn attestation is revoked
attestation.expiredAn attestation reaches its expiry date
attestation.supersededAn attestation is replaced by a newer version
Verificationverification.completedA verification check succeeds
verification.failedA verification check fails
Issuersissuer.createdA new issuer is registered
issuer.updatedAn issuer’s profile or settings change
issuer.suspendedAn issuer is suspended
Keyskey.createdA signing key is registered
key.rotatedA signing key is rotated
key.revokedA signing key is revoked
key.compromisedA key is reported as compromised
Teamteam.member_invitedA team invitation is sent
team.member_joinedA team member accepts an invitation
team.member_removedA team member is removed
team.role_changedA team member’s role is updated
Billingbilling.subscription.createdA new subscription is created
billing.subscription.updatedA subscription is modified
billing.invoice.createdA new invoice is generated
billing.usage.thresholdA usage threshold is reached
Consumerconsumer.content.protectedA consumer protects new content
Securitysecurity.password_changedA user changes their password
security.api_key_compromisedAn API key is flagged as compromised
security.suspicious_activitySuspicious account activity is detected

Wildcard filters

Use category.* to subscribe to every event in a category. For example, attestation.* matches attestation.created, attestation.revoked, attestation.expired, and attestation.superseded.

Endpoint limits by plan

The number of webhook endpoints you can create depends on your plan tier:
PlanEndpoint limit
Free1
Starter3
Business10
Enterprise25
Need more endpoints? Contact your account manager or upgrade your plan in Settings > Billing.

Creating an endpoint

  1. In the tenant console, go to Settings > Webhooks.
  2. Click Add endpoint.
  3. Enter a name, your HTTPS destination URL, and select the event types you want to receive.
  4. Click Create.
The console displays your endpoint secret once. Copy it immediately — you cannot retrieve it later.

Via the API

Request
POST /v1/webhooks/endpoints
X-API-Key: tl_live_...
Content-Type: application/json

{
  "name": "My Backend",
  "url": "https://api.example.com/webhooks/truthlock",
  "event_filters": ["attestation.*", "verification.completed"]
}
Response
{
  "id": "ep_abc123",
  "name": "My Backend",
  "url": "https://api.example.com/webhooks/truthlock",
  "status": "active",
  "secret": "whsec_...",
  "event_filters": ["attestation.*", "verification.completed"],
  "created_at": "2026-03-25T12:00:00Z"
}

Listing endpoints

Retrieve all webhook endpoints for your tenant:
Request
GET /v1/webhooks/endpoints
X-API-Key: tl_live_...
See the full API reference for response details.

Verifying signatures

Every webhook request includes a signature header for verification. Always verify signatures before processing events. Signature format:
X-Truthlocks-Signature: t=1710000000,v1=a1b2c3d4e5f6...
Where t is the Unix timestamp and v1 is the HMAC-SHA256 hex digest. Verification steps:
  1. Extract t (timestamp) and v1 (signature) from the header.
  2. Reject the request if the timestamp is more than 5 minutes old.
  3. Concatenate {timestamp}.{raw_request_body} to form the signing string.
  4. Compute HMAC-SHA256 of the signing string using your endpoint secret.
  5. Compare the computed digest to v1 using a constant-time comparison.
import crypto from "crypto";
import express from "express";

const app = express();
app.use(express.raw({ type: "application/json" }));

app.post("/webhooks/truthlock", (req, res) => {
  const sigHeader = req.headers["x-truthlocks-signature"] as string;
  if (!sigHeader) return res.status(401).send("Missing signature");

  const parts = Object.fromEntries(
    sigHeader.split(",").map((p) => p.split("=") as [string, string])
  );
  const timestamp = parts["t"];
  const signature = parts["v1"];

  // Reject stale requests (5-minute window)
  const age = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (age > 300) return res.status(401).send("Timestamp expired");

  // Compute expected signature
  const signingString = `${timestamp}.${req.body.toString()}`;
  const expected = crypto
    .createHmac("sha256", process.env.WEBHOOK_SECRET!)
    .update(signingString)
    .digest("hex");

  // Constant-time comparison
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return res.status(401).send("Invalid signature");
  }

  const event = JSON.parse(req.body.toString());
  console.log("Received event:", event.type);

  res.status(200).json({ received: true });
});
Always use a constant-time comparison function (like crypto.timingSafeEqual or hmac.compare_digest) to prevent timing attacks.

Request headers

Every webhook delivery includes these headers:
HeaderDescription
Content-Typeapplication/json
User-AgentTruthlock-Webhook-Service/1.0
X-Truthlocks-Event-IdUnique identifier for the event
X-Truthlocks-Event-TypeEvent type (e.g., attestation.created)
X-Truthlocks-TimestampUnix timestamp of the delivery attempt
X-Truthlocks-SignatureHMAC-SHA256 signature for verification

Retry behavior

If your endpoint returns a non-2xx status code or doesn’t respond within 5 seconds, Truthlocks retries the delivery with exponential backoff:
AttemptApproximate delay
1st retry~1 second
2nd retry~2 seconds
3rd retry~4 seconds
4th retry~16 seconds
5th retry~1 minute
6th retry~2 minutes
7th retry~5 minutes (max)
Delays include up to 30% jitter. After 8 total attempts (1 initial + 7 retries), the delivery is marked as failed. You can view delivery attempts and failure details in Settings > Webhooks by clicking on an endpoint, or query them via the API:
Request
GET /v1/webhooks/endpoints/{id}/deliveries
X-API-Key: tl_live_...
See the list deliveries API reference for response details.

Rotating secrets

If your webhook secret is compromised, rotate it immediately:
  1. In the tenant console, go to Settings > Webhooks and click on the endpoint.
  2. Click Rotate secret.
  3. Copy the new secret — the old secret stops working immediately.
You can also rotate via the API:
Request
POST /v1/webhooks/endpoints/{id}/rotate
X-API-Key: tl_live_...

Testing webhooks

Send a test event to verify your endpoint is working:
  1. In the tenant console, go to Settings > Webhooks and click on the endpoint.
  2. Click Send test.
  3. A webhook.test event is sent to your URL using the full signing and delivery pipeline.
Via the API:
Request
POST /v1/webhooks/test-delivery
X-API-Key: tl_live_...
Content-Type: application/json

{
  "endpoint_id": "ep_abc123",
  "event_type": "webhook.test",
  "payload": { "status": "ok", "source": "test-delivery" }
}
The event_type and payload fields are optional — they default to webhook.test and a basic status payload if omitted.

Best practices

Respond to webhooks quickly. Do your heavy processing asynchronously after returning a 200 response to avoid timeouts and retries.
  • Verify every signature. Never skip signature verification, even in development.
  • Use a message queue. Enqueue incoming events and process them in a worker to avoid blocking the HTTP response.
  • Handle duplicates. Use the X-Truthlocks-Event-Id header to deduplicate events in case of retries.
  • Monitor delivery failures. Check the deliveries tab in the console regularly for failed or dead deliveries.
  • Keep secrets secure. Store your webhook secret in environment variables, not in source code.