Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Webhooks

Receive real-time notifications when events occur in your StyleGrab account.

Endpoints

Register Webhook

Create a new webhook subscription.

POST /api/webhooks

Request Body:

{
  "url": "https://yoursite.com/webhooks/stylegrab",
  "events": ["extraction.completed", "diff.detected"],
  "secret": "your-webhook-secret"
}
FieldTypeRequiredDescription
urlstringYesHTTPS endpoint to receive events
eventsarrayYesEvents to subscribe to
secretstringNoSecret for HMAC signature (auto-generated if not provided)

Response:

{
  "id": "wh_abc123",
  "url": "https://yoursite.com/webhooks/stylegrab",
  "events": ["extraction.completed", "diff.detected"],
  "secret": "whsec_abc123...",
  "active": true,
  "created_at": "2024-01-15T10:30:00Z"
}

⚠️ Important: Store the secret securely. You’ll need it to verify webhook signatures.


List Webhooks

Get all registered webhooks.

GET /api/webhooks

Response:

{
  "data": [
    {
      "id": "wh_abc123",
      "url": "https://yoursite.com/webhooks/stylegrab",
      "events": ["extraction.completed", "diff.detected"],
      "active": true,
      "created_at": "2024-01-15T10:30:00Z"
    }
  ]
}

Update Webhook

Modify a webhook subscription.

PUT /api/webhooks/:id

Request Body:

{
  "url": "https://newsite.com/webhooks",
  "events": ["extraction.completed"],
  "active": false
}

Delete Webhook

Remove a webhook subscription.

DELETE /api/webhooks/:id

Events

extraction.completed

Fired when a CSS extraction finishes successfully.

{
  "event": "extraction.completed",
  "timestamp": "2024-01-15T10:30:02Z",
  "data": {
    "extraction_id": "ext_abc123",
    "url": "https://example.com",
    "snapshot_id": "snap_xyz789",
    "token_count": {
      "colors": 12,
      "typography": 3,
      "spacing": 8
    }
  }
}

diff.detected

Fired when changes are detected between snapshots.

{
  "event": "diff.detected",
  "timestamp": "2024-01-15T10:30:02Z",
  "data": {
    "extraction_id": "ext_abc123",
    "url": "https://example.com",
    "from_snapshot": "snap_abc123",
    "to_snapshot": "snap_xyz789",
    "changes": {
      "colors_changed": 3,
      "typography_changed": 1,
      "spacing_changed": 2,
      "total_changes": 6
    }
  }
}

snapshot.created

Fired when a new snapshot is stored.

{
  "event": "snapshot.created",
  "timestamp": "2024-01-15T10:30:02Z",
  "data": {
    "snapshot_id": "snap_xyz789",
    "extraction_id": "ext_abc123",
    "version": 3
  }
}

Signature Verification

All webhook payloads are signed using HMAC-SHA256. Verify the signature to ensure the request came from StyleGrab.

Headers

HeaderDescription
X-StyleGrab-SignatureHMAC-SHA256 signature
X-StyleGrab-TimestampUnix timestamp of the request

Verification Example (Node.js)

const crypto = require('crypto');

function verifyWebhook(payload, signature, timestamp, secret) {
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  // Use timing-safe comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express middleware
app.post('/webhooks/stylegrab', (req, res) => {
  const signature = req.headers['x-stylegrab-signature'];
  const timestamp = req.headers['x-stylegrab-timestamp'];
  
  if (!verifyWebhook(req.rawBody, signature, timestamp, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process the webhook
  const event = req.body;
  console.log(`Received ${event.event}`);
  
  res.status(200).send('OK');
});

Verification Example (Python)

import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    signed_payload = f"{timestamp}.{payload.decode()}"
    expected = hmac.new(
        secret.encode(),
        signed_payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

Retry Policy

StyleGrab retries failed webhook deliveries with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes

After 3 failed attempts, the webhook is marked as failed. Fix your endpoint and the next event will attempt delivery again.

Best Practices

  1. Respond quickly — Return 2xx within 5 seconds
  2. Process async — Queue the webhook for background processing
  3. Verify signatures — Always verify the HMAC signature
  4. Handle duplicates — Webhooks may be delivered more than once
  5. Use HTTPS — Webhook URLs must use HTTPS