Skip to main content

Webhooks

Receive real-time HTTP notifications when events occur in your tenant. Perfect for updating leaderboards, sending notifications, or syncing data.

Overview

Webhooks are HTTP callbacks that notify your server when specific events occur. Instead of polling the API, you receive push notifications in real-time.

Available Events

EventDescription
user.createdA new user registered in your tenant
user.updatedUser profile was updated
user.deletedUser was deleted
puzzle.startedA user started a puzzle
puzzle.completedA user completed a puzzle
achievement.unlockedA user unlocked an achievement
subscription.createdNew subscription started
subscription.cancelledSubscription cancelled
subscription.renewedSubscription renewed

Configuration

Configure webhooks via the API or dashboard:

cURL
curl -X POST "https://api.puzzlesection.app/v1/webhooks" \
-H "X-API-Key: ps_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/puzzle-section",
"events": ["puzzle.completed", "achievement.unlocked"]
}'

Response:

JSON
{
"id": "wh_abc123",
"url": "https://your-server.com/webhooks/puzzle-section",
"events": ["puzzle.completed", "achievement.unlocked"],
"status": "active",
"createdAt": "2026-01-09T10:30:00Z"
}

Payload Format

All webhook payloads follow this structure:

JSON
1{
2 "id": "evt_xyz789",
3 "type": "puzzle.completed",
4 "timestamp": "2026-01-09T14:23:45Z",
5 "data": {
6 "userId": "usr_abc123",
7 "puzzleId": "pzl_sudoku_2026-01-09_medium",
8 "puzzleType": "sudoku",
9 "difficulty": "medium",
10 "timeMs": 423000,
11 "score": 8750,
12 "rank": 234
13 }
14}

Example: Achievement Unlocked

JSON
1{
2 "id": "evt_abc456",
3 "type": "achievement.unlocked",
4 "timestamp": "2026-01-09T14:23:45Z",
5 "data": {
6 "userId": "usr_abc123",
7 "achievement": {
8 "id": "streak_30",
9 "name": "Monthly Master",
10 "description": "Complete puzzles for 30 consecutive days"
11 }
12 }
13}

Signature Verification

Verify webhook signatures to ensure requests are from The Puzzle Section:

Always verify signatures

Never trust webhook payloads without verifying the signature. Attackers could spoof requests to your endpoint.

Each request includes a X-Puzzle-Signature header:

HTTP
POST /webhooks/puzzle-section HTTP/1.1
Host: your-server.com
Content-Type: application/json
X-Puzzle-Signature: t=1704806625,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
X-Puzzle-Timestamp: 1704806625

Verification Example (Node.js)

TypeScript
1import crypto from 'crypto';
2
3function verifyWebhookSignature(
4 payload: string,
5 signature: string,
6 secret: string
7): boolean {
8 const [timestamp, hash] = signature
9 .split(',')
10 .map(part => part.split('=')[1]);
11
12 // Verify timestamp is recent (within 5 minutes)
13 const now = Math.floor(Date.now() / 1000);
14 if (Math.abs(now - parseInt(timestamp)) > 300) {
15 return false; // Replay attack protection
16 }
17
18 // Compute expected signature
19 const signedPayload = `${timestamp}.${payload}`;
20 const expectedHash = crypto
21 .createHmac('sha256', secret)
22 .update(signedPayload)
23 .digest('hex');
24
25 // Constant-time comparison
26 return crypto.timingSafeEqual(
27 Buffer.from(hash),
28 Buffer.from(expectedHash)
29 );
30}
31
32// Usage in Express
33app.post('/webhooks/puzzle-section', (req, res) => {
34 const signature = req.headers['x-puzzle-signature'] as string;
35 const payload = JSON.stringify(req.body);
36
37 if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
38 return res.status(401).json({ error: 'Invalid signature' });
39 }
40
41 // Process the webhook...
42 res.status(200).json({ received: true });
43});

Best Practices

  • Respond quickly — Return a 2xx response within 5 seconds. Process events asynchronously if needed.
  • Handle retries — We retry failed deliveries with exponential backoff. Use the event ID for idempotency.
  • Verify signatures — Always verify the X-Puzzle-Signature header.
  • Use HTTPS — Webhook endpoints must use HTTPS for security.
  • Log events — Store webhook events for debugging and audit trails.

Retry Policy

Failed webhook deliveries are retried with exponential backoff:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry (final)24 hours

After 5 failed attempts, the webhook is marked as failed and you'll receive an email notification.