Skip to main content
Jamie offers two authentication methods for webhooks. Choose the one that best fits your needs.

Authentication Methods

The simplest way to verify webhook requests. Jamie sends a static API key in a header that you specify during webhook creation. How it works:
  1. When creating the webhook, choose “API Key” authentication
  2. Optionally specify a custom header name (default: x-jamie-api-key)
  3. Save the generated secret key (sk_...)
  4. In your webhook handler, compare the header value with your stored secret

Verification Code Examples

const express = require('express');
const app = express();

app.use(express.json());

app.post('/webhooks/jamie', (req, res) => {
  // Get the API key from header (use your custom header name if configured)
  const apiKey = req.headers['x-jamie-api-key'];
  
  // Compare with your stored secret
  if (apiKey !== process.env.JAMIE_WEBHOOK_SECRET) {
    console.error('Invalid API key');
    return res.status(401).send('Unauthorized');
  }
  
  // API key is valid, process the webhook
  const { data } = req.body;
  console.log('Meeting completed:', data.event.title);
  console.log('Summary:', data.summary.markdown);
  
  // Process tasks
  data.tasks.forEach(task => {
    console.log('Task:', task.content);
  });
  
  res.status(200).send('OK');
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});

Signature Verification (Advanced)

For maximum security, Jamie can sign all webhook requests using HMAC-SHA256. This ensures requests are authentic and haven’t been tampered with.

Signature Format

The x-jamie-signature header uses the following format:
t=<timestamp>,v0=<signature>
  • t: Unix timestamp (seconds) when the signature was created
  • v0: HMAC-SHA256 signature of the payload

Verification Steps

  1. Extract the timestamp and signature from the x-jamie-signature header
  2. Validate the timestamp - Reject requests with timestamps older than 5 minutes (300 seconds) to prevent replay attacks
  3. Recreate the signed message - Concatenate the timestamp, a period (.), and the raw request body: {timestamp}.{raw_body}
  4. Compute the expected signature - Generate an HMAC-SHA256 hash of the message using your signing secret
  5. Compare signatures - Use a constant-time comparison to prevent timing attacks

Verification Code Examples

const crypto = require('crypto');

async function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): Promise<boolean> {
  // Parse signature header: t=timestamp,v0=hash
  const parts = signature.split(',');
  const timestamp = parts[0].split('=')[1];
  const expectedSignature = parts[1].split('=')[1];

  // Validate timestamp (prevent replay attacks - 5 min tolerance)
  const now = Math.floor(Date.now() / 1000);
  if (now - parseInt(timestamp) > 300) {
    throw new Error('Signature expired');
  }

  // Recreate the signed message
  const message = `${timestamp}.${payload}`;

  // Generate HMAC signature
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(message);
  const actualSignature = hmac.digest('hex');

  // Compare signatures using constant-time comparison
  const expectedBuffer = Buffer.from(expectedSignature, 'hex');
  const actualBuffer = Buffer.from(actualSignature, 'hex');
  
  if (!crypto.timingSafeEqual(expectedBuffer, actualBuffer)) {
    throw new Error('Invalid signature');
  }

  return true;
}

// Usage in your webhook endpoint (Express example):
app.post('/webhooks/jamie', async (req, res) => {
  const signature = req.headers['x-jamie-signature'];
  const payload = JSON.stringify(req.body);
  
  try {
    await verifyWebhookSignature(
      payload,
      signature,
      process.env.JAMIE_WEBHOOK_SECRET
    );
    
    // Signature is valid, process the webhook
    const { data } = req.body;
    console.log('Meeting completed:', data.event.title);
    
    res.status(200).send('OK');
  } catch (error) {
    console.error('Webhook verification failed:', error);
    res.status(401).send('Unauthorized');
  }
});
Security Best Practices:
  • Always verify the API key or signature before processing webhook data
  • For signature verification, use constant-time comparison to prevent timing attacks
  • Validate timestamps to prevent replay attacks (recommended tolerance: 5 minutes)
  • Store your secret key securely (use environment variables or a secrets manager)
  • Never commit secret keys to version control