Webhooks

Webhooks are the core of Notifs. They allow you to send notifications to multiple channels with a single API call. This guide covers everything you need to know about creating, configuring, and using webhooks.

What are Webhooks?

A webhook in Notifs is a notification endpoint that you can trigger via our API or SDK. When you send data to a webhook, Notifs automatically delivers it to all configured channels (Email, Slack, SMS, Discord, etc.).

Key Concepts

  • Webhook ID: Unique identifier for your webhook (e.g., webhook_abc123)
  • Channels: Delivery destinations (Email, Slack, SMS, etc.)
  • Payload: The data you send with each webhook request
  • Template: Optional message template for formatting notifications

Creating a Webhook

Via Dashboard

  1. Navigate to Webhooks in your dashboard

  2. Click Create Webhook

  3. Configure your webhook:

    • Name: Descriptive name (e.g., "Payment Success")
    • Channels: Select delivery channels
    • Template: Optional message template
    • Secret: Auto-generated signing secret
  4. Save and copy the Webhook ID

Via API

import { Notifs } from '@notifs/sdk'

const notifs = new Notifs({
  apiKey: process.env.NOTIFS_API_KEY
})

const webhook = await notifs.webhooks.create({
  name: 'Payment Success',
  channels: ['email', 'slack'],
  template: {
    email: {
      subject: 'Payment Received - {{amount}}',
      body: 'Thank you {{user}}! Your payment of {{amount}} has been received.'
    },
    slack: {
      text: 'New payment: {{amount}} from {{user}}'
    }
  }
})

console.log(webhook.id) // Use this to send webhooks
console.log(webhook.secret) // Use this to verify webhook signatures

Configuring Channels

Each webhook can deliver to multiple channels simultaneously. Configure each channel with the appropriate credentials and settings.

Email

Configure your email provider (Mailgun, SendGrid, AWS SES, etc.):

await notifs.channels.configure('email', {
  provider: 'mailgun',
  apiKey: process.env.MAILGUN_API_KEY,
  domain: 'mail.yourapp.com',
  fromEmail: 'notifications@yourapp.com',
  fromName: 'Your App'
})

Slack

Add Slack integration via webhook URL or OAuth:

await notifs.channels.configure('slack', {
  webhookUrl: process.env.SLACK_WEBHOOK_URL,
  channel: '#notifications',
  username: 'Notifs Bot',
  iconEmoji: ':bell:'
})

SMS

Configure Twilio for SMS delivery:

await notifs.channels.configure('sms', {
  provider: 'twilio',
  accountSid: process.env.TWILIO_ACCOUNT_SID,
  authToken: process.env.TWILIO_AUTH_TOKEN,
  fromNumber: '+1234567890'
})

Discord

Add Discord via webhook URL:

await notifs.channels.configure('discord', {
  webhookUrl: process.env.DISCORD_WEBHOOK_URL,
  username: 'Notifs Bot',
  avatarUrl: 'https://yourapp.com/avatar.png'
})

Sending Webhooks

Basic Send

await notifs.webhooks.send('webhook_abc123', {
  user: 'john@example.com',
  event: 'payment_success',
  amount: '$99.00'
})

With Idempotency

Prevent duplicate sends with idempotency keys:

await notifs.webhooks.send('webhook_abc123', {
  user: 'john@example.com',
  event: 'payment_success',
  amount: '$99.00'
}, {
  idempotencyKey: `payment_${paymentId}`
})

If you send the same idempotency key within 24 hours, Notifs returns the cached response without sending duplicate notifications.

With Metadata

Attach metadata for tracking and debugging:

await notifs.webhooks.send('webhook_abc123', {
  user: 'john@example.com',
  amount: '$99.00'
}, {
  metadata: {
    userId: 'user_456',
    invoiceId: 'inv_789',
    environment: 'production'
  }
})

Webhook Templates

Templates allow you to format messages for each channel using variables from your payload.

Template Syntax

Use double curly braces for variables: {{variableName}}

Example Templates

Email Template:

{
  subject: 'Order #{{orderId}} Confirmed',
  body: `
    Hi {{customerName}},

    Your order #{{orderId}} has been confirmed!

    Total: {{total}}
    Estimated delivery: {{deliveryDate}}

    Track your order: {{trackingUrl}}
  `
}

Slack Template:

{
  text: ':white_check_mark: Order #{{orderId}} confirmed',
  blocks: [
    {
      type: 'section',
      text: {
        type: 'mrkdwn',
        text: '*Order Confirmed*\nOrder #{{orderId}} for {{customerName}}'
      }
    },
    {
      type: 'section',
      fields: [
        { type: 'mrkdwn', text: '*Total:*\n{{total}}' },
        { type: 'mrkdwn', text: '*Delivery:*\n{{deliveryDate}}' }
      ]
    }
  ]
}

Webhook Retries

Notifs automatically retries failed webhook deliveries with exponential backoff:

  • Retry 1: After 1 second
  • Retry 2: After 2 seconds
  • Retry 3: After 4 seconds
  • Retry 4: After 8 seconds
  • Retry 5: After 16 seconds

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

Manual Retry

Retry a failed webhook manually:

await notifs.webhooks.retry('log_xyz789')

Webhook Logs

View webhook delivery logs in your dashboard or via API:

const logs = await notifs.logs.list({
  webhookId: 'webhook_abc123',
  limit: 50
})

for (const log of logs.data) {
  console.log(`${log.timestamp}: ${log.status}`)
  if (log.error) {
    console.error(`Error: ${log.error}`)
  }
}

Log Retention

  • Free Tier: 7 days
  • Pro Tier: 30 days
  • Enterprise: Custom retention

Rate Limits

Webhook sending is subject to rate limits based on your plan:

| Plan | Rate Limit | Monthly Quota | |------|------------|---------------| | Free | 10/second | 1,000 webhooks | | Pro | 100/second | 100,000 webhooks | | Enterprise | Custom | Unlimited |

Webhook Security

Signature Verification

Every webhook request includes an HMAC-SHA256 signature in the X-Notifs-Signature header. Always verify this signature to ensure requests are genuine.

See the Security documentation for implementation details.

Secret Rotation

Rotate webhook secrets regularly:

const webhook = await notifs.webhooks.rotateSecret('webhook_abc123')
console.log(webhook.secret) // New secret

Important: Update your verification code with the new secret before rotating to prevent downtime.

Testing Webhooks

Test Mode

Use test mode to send webhooks without actually delivering them:

await notifs.webhooks.send('webhook_abc123', {
  user: 'test@example.com'
}, {
  testMode: true
})

Test mode webhooks appear in logs but aren't delivered to channels.

Webhook Inspector

View real-time webhook requests in the dashboard inspector:

  1. Go to WebhooksInspector
  2. Select your webhook
  3. See all incoming requests and delivery status in real-time

Common Patterns

User Notifications

async function notifyUser(userId: string, event: string, data: any) {
  await notifs.webhooks.send('user_notifications', {
    userId,
    event,
    ...data
  }, {
    idempotencyKey: `${userId}_${event}_${Date.now()}`,
    metadata: { userId, event }
  })
}

// Usage
await notifyUser('user_123', 'password_changed', {
  email: 'user@example.com',
  timestamp: new Date().toISOString()
})

System Alerts

async function sendAlert(severity: string, message: string) {
  await notifs.webhooks.send('system_alerts', {
    severity,
    message,
    timestamp: new Date().toISOString(),
    hostname: process.env.HOSTNAME
  }, {
    metadata: { severity, alertType: 'system' }
  })
}

// Usage
await sendAlert('critical', 'Database connection pool exhausted')

Batch Notifications

async function sendBatchNotifications(users: User[], event: string) {
  const promises = users.map(user =>
    notifs.webhooks.send('batch_notifications', {
      userId: user.id,
      email: user.email,
      event,
      timestamp: new Date().toISOString()
    }, {
      idempotencyKey: `batch_${event}_${user.id}`,
      metadata: { userId: user.id, batchId: 'batch_123' }
    })
  )

  await Promise.all(promises)
}

Best Practices

  1. Use Idempotency Keys - Always provide idempotency keys for important operations
  2. Include Metadata - Add metadata for easier debugging and tracking
  3. Verify Signatures - Always verify webhook signatures in production
  4. Handle Failures - Implement proper error handling and retry logic
  5. Monitor Logs - Regularly check webhook logs for failed deliveries
  6. Test Thoroughly - Use test mode to verify webhook behavior before going live
  7. Rotate Secrets - Rotate webhook secrets periodically for security

Troubleshooting

Webhook Not Delivered

  1. Check webhook logs for error messages
  2. Verify channel credentials are correct
  3. Ensure rate limits haven't been exceeded
  4. Check that the webhook is active

Slow Delivery

  1. Check rate limits - you may be hitting throttling
  2. Verify channel provider status (e.g., Slack, Mailgun)
  3. Contact support for Enterprise plan optimization

Duplicate Deliveries

  1. Ensure you're using idempotency keys
  2. Check for retry logic in your code
  3. Review webhook logs for duplicate requests

Next Steps