Webhooks

Receive real-time events from GrenLogger when things happen in your organization. Configure webhooks in the dashboard and verify payloads using the Standard Webhooks signature scheme.

Real-time notifications

When you activate remote logging for a user, create or delete a project, or exceed an error threshold, GrenLogger sends a signed webhook to your configured URL. Respond with 2xx within 15 seconds to acknowledge receipt.

Event types

You can subscribe to these events when creating a webhook:

  • remote_activation.added – Remote log activation added for a user
  • remote_activation.removed – Remote log activation removed
  • project.created – New project created
  • project.updated – Project updated
  • project.deleted – Project deleted
  • member.invited – Team member invited
  • member.removed – Team member removed
  • log.error.threshold_exceeded – Error count in last 24h exceeded tier threshold

Payload format

Webhooks follow the Standard Webhooks spec. Each request includes:

  • Headers: webhook-id, webhook-timestamp, webhook-signature
  • Body: JSON with type, timestamp (ISO 8601), and data
{
  "type": "remote_activation.added",
  "timestamp": "2024-01-15T14:30:00.000Z",
  "data": {
    "projectId": "proj_abc123",
    "userId": "user_xyz789",
    "expiresAt": "2024-01-16T14:30:00.000Z",
    "activatedBy": "uid_owner"
  }
}

Verifying signatures

Use HMAC-SHA256 to verify the payload. The signed content is:

webhook-id.webhook-timestamp.raw_body

The signature header format is v1,base64_signature. Use your webhook secret (shown once when creating the webhook) to compute the HMAC and compare with constant-time comparison.

Example: Node.js verification

const crypto = require('crypto');

function verifyWebhook(payload, headers, secret) {
  const webhookId = headers['webhook-id'];
  const timestamp = headers['webhook-timestamp'];
  const signature = headers['webhook-signature'];
  if (!webhookId || !timestamp || !signature) return false;

  const signedContent = webhookId + '.' + timestamp + '.' + payload;
  const rawSecret = Buffer.from(secret.replace(/^whsec_/, '').replace(/-/g, '+').replace(/_/g, '/'), 'base64');
  const expected = 'v1,' + crypto.createHmac('sha256', rawSecret).update(signedContent).digest('base64');
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
}

Best practices

  • Respond with 2xx within 10–15 seconds to avoid retries
  • Use the webhook-id as an idempotency key to avoid processing duplicates
  • Verify webhook-timestamp is within a few minutes to prevent replay attacks
  • Process webhooks asynchronously (queue and respond quickly)

Setup

  1. Go to your project in the dashboard
  2. Open the Webhooks section
  3. Add a webhook URL (HTTPS required)
  4. Select the events you want to receive
  5. Save the secret shown once—you will need it to verify signatures

Configure webhooks

Webhooks are available on Expert and higher plans.

Open Dashboard

Related