SyncNexaSyncNexa
Docs
v1.0 (Latest)

Webhooks & HMAC Signatures

v1.0

Technical reference for webhook event schemas, cryptographic signature validation, delivery retries, and endpoint management.

Last updated: August 2026

SyncNexa webhooks deliver secure, event-driven HTTP POST notifications directly to your application backend.

Webhook Delivery Headers

HeaderFormatDescription
X-SyncNexa-Signaturet=1724155200,v1=9a8b...Timestamp and HMAC-SHA256 signature for payload verification
X-SyncNexa-Eventverification.completedThe specific event identifier for routing
X-SyncNexa-Deliverydel_9f8e7d6c5b4aUnique delivery attempt UUID for idempotency tracking
Content-Typeapplication/jsonJSON payload encoding
User-AgentSyncNexa-Webhooks/1.0Standard webhook user agent string

Event Schemas & Payloads

Sample verification.completed event payload:

verification.completed.jsonjson
1{
2 "id": "evt_0a1b2c3d4e5f",
3 "event": "verification.completed",
4 "createdAt": "2026-08-20T12:30:00.000Z",
5 "appId": "app_8a7b6c5d4e3f",
6 "environment": "live",
7 "data": {
8 "sessionId": "sess_9f8e7d6c5b4a",
9 "verified": true,
10 "university": {
11 "name": "University College London",
12 "domain": "ucl.ac.uk",
13 "country": "GB"
14 },
15 "claims": {
16 "is_active_student": true,
17 "academic_level": "Undergraduate",
18 "valid_until": "2027-06-30T23:59:59Z"
19 }
20 }
21}

Verifying HMAC-SHA256 Signatures

Verify the raw request body with your secret key to prevent replay attacks and man-in-the-middle tampering:

typescript
1import crypto from 'crypto';
2 
3export function verifySyncNexaWebhook(
4 rawBody: string | Buffer,
5 signatureHeader: string,
6 secret: string,
7 toleranceSeconds: number = 300
8): boolean {
9 const parts = signatureHeader.split(',');
10 const timestamp = parts.find((p) => p.startsWith('t='))?.split('=')[1];
11 const signature = parts.find((p) => p.startsWith('v1='))?.split('=')[1];
12 
13 if (!timestamp || !signature) return false;
14 
15 // Check timestamp freshness to prevent replay attacks
16 const now = Math.floor(Date.now() / 1000);
17 if (Math.abs(now - parseInt(timestamp, 10)) > toleranceSeconds) {
18 return false;
19 }
20 
21 const payload = `${timestamp}.${rawBody.toString()}`;
22 const computed = crypto
23 .createHmac('sha256', secret)
24 .update(payload)
25 .digest('hex');
26 
27 return crypto.timingSafeEqual(
28 Buffer.from(computed),
29 Buffer.from(signature)
30 );
31}

Managing Subscriptions via API

POST/org/v1/webhooks
Bearer Auth

Create Webhook Subscription

Registers a new webhook URL and subscribes to specified event triggers.

Was this page helpful?