Webhook Integration Guide
Receive real-time event notifications via HTTPS POST to your endpoints.
Overview
Webhooks push event data to your server via HTTPS POST requests in real-time. Instead of polling the API for changes, webhooks notify you immediately when events occur — such as a candidate connecting, a profile updating, or a credential being issued.
- Events are delivered as JSON payloads to your configured endpoint
- Each delivery is signed with HMAC-SHA256 for verification
- Failed deliveries are retried with exponential backoff
- Events are guaranteed at-least-once delivery
Setup Steps
- Create Endpoint — Developer Portal → Webhooks → Add Endpoint. Provide your HTTPS URL.
- Select Events — Choose which events to subscribe to (or select all).
- Copy Signing Secret — Store the
whsec_...secret securely for signature verification. - Test & Activate — Send a test event to verify your endpoint responds with HTTP 2xx.
Available Events
| Event | Description |
|---|---|
candidate.connected | Candidate connected to your organization |
candidate.disconnected | Candidate disconnected from your organization |
candidate.profile_updated | Candidate updated their profile information |
candidate.record_added | New verified record added to candidate profile |
candidate.tei_changed | Candidate's Trust & Employability Index score changed |
assessment.result_published | Assessment results published for a candidate |
assessment.certificate_generated | Assessment certificate generated and available |
credential.issued | Verifiable credential issued to candidate |
credential.verified | Credential verification completed |
Payload Format
All webhook payloads follow a consistent structure:
{
"id": "evt_abc123def456",
"type": "candidate.connected",
"api_version": "v1",
"created_at": "2026-08-12T14:30:00Z",
"data": {
"gpin": "GPIN12345",
"organization_id": "org_xyz789",
"candidate": {
"name": "Jane Smith",
"email": "jane@example.com",
"tei_score": 82
}
}
}
id— Unique event identifier (use for deduplication)type— Event type from the table aboveapi_version— API version that generated the eventcreated_at— ISO 8601 timestampdata— Event-specific payload
Signature Verification
Every webhook delivery includes a cryptographic signature so you can verify it came from GenuineIN.
Headers Included
| Header | Description |
|---|---|
X-Webhook-Signature | sha256= + HMAC-SHA256 hex digest of the raw JSON body |
X-Webhook-Timestamp | ISO 8601 timestamp of when the delivery was sent |
X-Webhook-Event | Event category (e.g. career_api) |
Verification Formula
expected = "sha256=" + HMAC-SHA256(webhook_secret, raw_json_body)
valid = (expected === X-Webhook-Signature header)
Node.js Example
const crypto = require('crypto');
function verifyWebhook(req, webhookSecret) {
const signatureHeader = req.headers['x-webhook-signature']; // "sha256=abc123..."
const body = req.rawBody; // Raw JSON string
const expected = 'sha256=' + crypto
.createHmac('sha256', webhookSecret)
.update(body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected))) {
throw new Error('Invalid webhook signature');
}
return JSON.parse(body);
}
Python Example
import hmac, hashlib
def verify_webhook(headers, body, webhook_secret):
signature_header = headers['X-Webhook-Signature'] # "sha256=abc123..."
expected = 'sha256=' + hmac.new(
webhook_secret.encode(),
body.encode(),
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature_header, expected):
raise ValueError('Invalid webhook signature')
return json.loads(body)
Retry Policy
If your endpoint does not respond with HTTP 2xx within 30 seconds, we retry with exponential backoff:
| Attempt | Delay After Failure |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 2 minutes |
| 4 | 4 minutes |
| 5 | 8 minutes |
| FAILED | Event marked as permanently failed (~15 minutes total elapsed) |
Success criteria: Your endpoint must respond with HTTP 2xx within 30 seconds. Any other response (including 3xx redirects) triggers a retry.
Best Practices
| Practice | Why |
|---|---|
| Respond quickly (return 200 immediately) | Process async after acknowledging to avoid timeouts |
| Verify the signature | Ensure the request came from GenuineIN |
| Check timestamp (reject > 5 min old) | Prevent replay attacks |
| Handle duplicates gracefully | At-least-once delivery may send the same event twice |
Use event id as dedup key | Idempotent processing prevents side-effect duplication |
Testing
Use the Developer Portal to send test events to your endpoint:
- Go to Developer Portal → Webhooks → your endpoint
- Click "Send Test Event"
- Select the event type to simulate
- Verify your endpoint responds with 200
Manual Test with curl
curl -X POST https://your-server.com/webhooks/genuinein \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: sha256=test_signature_here" \
-H "X-Webhook-Timestamp: 2026-08-12T14:30:00.000Z" \
-H "X-Webhook-Event: career_api" \
-d '{"id":"evt_test123","type":"candidate.connected","api_version":"v1","created_at":"2026-08-12T14:30:00Z","data":{"gpin":"GPIN12345"}}'