Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.grantiva.io/llms.txt

Use this file to discover all available pages before exploring further.

Webhooks are available on Pro, Business, and Enterprise plans.

1. Create an endpoint

In the dashboard, go to Settings > Webhooks and click Create Endpoint. Enter your HTTPS endpoint URL and select which events to listen for:
EventDescription
device.newFirst attestation from a new device
device.high_riskDevice exceeds risk threshold
device.attestation_failedAttestation validation failed
attestation.anomalyUnusual attestation pattern
Grantiva generates a signing secret (whsec_...) — save this for signature verification.

2. Handle webhook events

// Node.js / Express example
const crypto = require('crypto');

app.post('/webhooks/grantiva', (req, res) => {
  // Verify signature
  const signature = req.headers['x-grantiva-signature'];
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(JSON.stringify(req.body))
    .digest('hex');

  if (signature !== expected) {
    return res.status(401).send('Invalid signature');
  }

  // Process event
  const { event, data } = req.body;

  switch (event) {
    case 'device.high_risk':
      console.log(`High risk device: ${data.device_id}, score: ${data.risk_score}`);
      blockDevice(data.device_id);
      break;
    case 'device.new':
      console.log(`New device: ${data.device_id}`);
      break;
  }

  res.sendStatus(200);
});
// Vapor example
func handleWebhook(_ req: Request) throws -> HTTPStatus {
    let signature = req.headers.first(name: "X-Grantiva-Signature") ?? ""
    let body = req.body.data ?? ByteBuffer()

    let key = SymmetricKey(data: Data(Environment.get("WEBHOOK_SECRET")!.utf8))
    let mac = HMAC<SHA256>.authenticationCode(for: Data(buffer: body), using: key)
    let expected = "sha256=" + mac.map { String(format: "%02x", $0) }.joined()

    guard expected == signature else {
        throw Abort(.unauthorized)
    }

    let payload = try req.content.decode(WebhookPayload.self)

    switch payload.event {
    case "device.high_risk":
        // Handle high risk device
        break
    default:
        break
    }

    return .ok
}

3. Test your endpoint

From the webhook detail page in the dashboard, click Send Test Event. This fires a webhook.test event to verify your endpoint is reachable.

4. Verify it works

Check the delivery log in the dashboard. Each delivery shows:
  • HTTP status code
  • Response body
  • Delivery time
  • Retry count

Retries

Failed deliveries (non-2xx response or timeout) are retried up to 3 times with exponential backoff:
AttemptDelay
1st retry~1 minute
2nd retry~5 minutes
3rd retry~30 minutes

Next steps