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 UUID identifier for your webhook
- Webhook Secret: Secret key used to sign requests (HMAC-SHA256)
- Services: Delivery destinations configured for each webhook (Email, Slack, SMS)
- Payload: The data you send with each notification request (
title,message,data)
Creating a Webhook
Via Dashboard
- Navigate to Webhooks in your dashboard
- Click Create Webhook
- Configure your webhook:
- Name: Descriptive name (e.g., "Payment Notifications")
- Project: Optional project to organize webhooks
- Save and copy the Webhook ID and Webhook Secret
- Add services (Email, Slack, SMS) to configure delivery destinations
Via SDK
import { Notifs } from '@notifs/sdk'
const notifs = new Notifs({
apiKey: process.env.NOTIFS_API_KEY
})
const webhook = await notifs.webhooks.create({
name: 'Payment Notifications',
projectId: 'optional-project-uuid' // Optional
})
console.log(webhook.id) // Webhook ID for sending notifications
console.log(webhook.webhook_secret) // Secret for signature verification
Note: Services (Email, Slack, SMS) are configured via the dashboard after creating the webhook.
Configuring Services
Each webhook can deliver to multiple services simultaneously. Services are configured via the dashboard.
- Go to your webhook in the dashboard
- Click Add Service → Email
- Configure:
- To: Recipient email address
- Subject: Email subject line (optional)
Slack
- Go to your webhook in the dashboard
- Click Add Service → Slack
- Click Connect Slack to authorize via OAuth
- Select up to 3 channels to post notifications
SMS
- Go to your webhook in the dashboard
- Click Add Service → SMS
- Add phone numbers in E.164 format (e.g.,
+14155551234)
Sending Notifications
Basic Send
First get the webhook, then send notifications:
import { Notifs } from '@notifs/sdk'
const notifs = new Notifs({
apiKey: process.env.NOTIFS_API_KEY
})
// Get webhook once, reuse for multiple sends
const webhook = await notifs.webhooks.get('your-webhook-id')
// Send a notification
await webhook.send({
title: 'Payment Received',
message: 'Your payment of $99.00 has been processed',
data: {
user: 'john@example.com',
amount: '$99.00',
orderId: 'order_123'
}
})
Payload Structure
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| title | string | Yes | Notification title |
| message | string | No | Notification message body |
| data | object | No | Custom data passed to services |
Response
const response = await webhook.send({
title: 'Payment Received',
data: { amount: '$99.00' }
})
console.log(response.notificationId) // Unique notification ID
console.log(response.servicesExecuted) // true if services ran
console.log(response.usageInfo) // Current usage stats
Duplicate Prevention
Notifs automatically prevents duplicate notifications within a 5-minute window. If you send an identical payload, you'll receive a 409 Conflict response.
To send the same notification again, either:
- Wait 5 minutes
- Add a unique field like a timestamp to your payload
Payload Data
The data you send is passed directly to each configured service. Structure your payload with fields that make sense for your notification.
Recommended Fields
await webhook.send({
title: 'Order Confirmed', // Used as email subject, Slack header
message: 'Your order is on the way', // Main notification body
data: {
// Custom fields for your services
orderId: 'order_123',
customerName: 'John Doe',
total: '$99.00',
trackingUrl: 'https://...'
}
})
How Services Use Data
| Service | Title | Message | Data | |---------|-------|---------|------| | Email | Subject line | Email body | Included in body | | Slack | Bold header | Message text | Formatted fields | | SMS | Prefix | SMS content | Appended to message |
Example Payloads
Order Notification:
{
title: 'Order #12345 Shipped',
message: 'Your order is on the way!',
data: {
trackingNumber: 'TRACK123',
estimatedDelivery: '2024-01-15',
carrier: 'FedEx'
}
}
Alert Notification:
{
title: '[CRITICAL] Server Down',
message: 'Production server is not responding',
data: {
server: 'prod-api-1',
lastSeen: '2024-01-10T15:30:00Z',
region: 'us-east-1'
}
}
Service Executions
Each notification triggers service executions for all configured services (Email, Slack, SMS). You can view execution status and rerun failed executions.
Execution Status
- success - Service delivered successfully
- error - Service failed (can be rerun)
- skipped - Skipped due to usage limits
Manual Rerun
Rerun failed service executions via the dashboard:
- Go to Webhooks → Select your webhook
- Click on a notification to see service executions
- Click Rerun on any failed execution
Reruns count toward your usage limit and are tracked with an incrementing rerun_number.
Webhook Logs
View request logs for debugging in the dashboard:
- Go to Webhooks → Select your webhook
- Click Logs tab
- View all incoming requests with:
- Request payload
- Response status
- Signature validation status
- Processing duration
Filtering Logs
Filter logs by status:
- Success - HTTP 2xx responses
- Error - HTTP 4xx/5xx responses
Log Data
Each log entry includes:
request_body- The payload sentresponse_status- HTTP status codesignature_valid- Whether signature verification passedduration_ms- Processing time in milliseconds
Rate Limits
Notification sending is subject to rate limits:
| Tier | Rate Limit | |------|------------| | Per IP | Configurable | | Per Webhook | Configurable | | Per User | Configurable |
If you exceed rate limits, you'll receive a 429 Too Many Requests response with a Retry-After header.
Usage Limits
Service executions are tracked against your plan's monthly limit:
| Plan | Service Executions | |------|-------------------| | Free | Limited | | Pro | Higher limit | | Enterprise | Custom |
When you exceed your limit, services are marked as skipped. A grace period of 5 additional executions is allowed before hard blocking.
Webhook Security
Signature Verification
Every request to the notification endpoint must include an HMAC-SHA256 signature:
X-Notifs-Signature: t=<timestamp>,v1=<hash>
The SDK handles signature generation automatically. For manual implementation, see Security.
Secret Regeneration
Regenerate webhook secrets via the dashboard:
- Go to Webhooks → Select your webhook
- Click Settings → Regenerate Secret
- Update your code with the new secret
Important: The old secret is invalidated immediately.
Testing Webhooks
Send Test Notification
Test your webhook configuration via the dashboard:
- Go to Webhooks → Select your webhook
- Click Test Webhook
- A test notification is sent through all configured services
Test Payload
The test notification includes:
{
"title": "Test Notification",
"message": "This is a test notification from your webhook",
"timestamp": "2024-01-01T00:00:00.000Z",
"test": true
}
Common Patterns
User Notifications
import { Notifs } from '@notifs/sdk'
const notifs = new Notifs({ apiKey: process.env.NOTIFS_API_KEY })
const userWebhook = await notifs.webhooks.get('your_user_webhook_id')
async function notifyUser(userId: string, event: string, data: any) {
await userWebhook.send({
title: `User Event: ${event}`,
message: data.message,
data: {
userId,
event,
...data,
timestamp: new Date().toISOString()
}
})
}
// Usage
await notifyUser('user_123', 'password_changed', {
message: 'Your password was changed',
email: 'user@example.com'
})
System Alerts
const alertWebhook = await notifs.webhooks.get('your_alert_webhook_id')
async function sendAlert(severity: string, message: string) {
await alertWebhook.send({
title: `[${severity.toUpperCase()}] Alert`,
message,
data: {
severity,
timestamp: new Date().toISOString(),
hostname: process.env.HOSTNAME
}
})
}
// Usage
await sendAlert('critical', 'Database connection pool exhausted')
Batch Notifications
const batchWebhook = await notifs.webhooks.get('your_batch_webhook_id')
async function sendBatchNotifications(users: User[], event: string) {
const promises = users.map(user =>
batchWebhook.send({
title: `New ${event}`,
data: {
userId: user.id,
email: user.email,
event,
timestamp: new Date().toISOString()
}
})
)
await Promise.allSettled(promises)
}
Best Practices
- Reuse Webhook Instances - Get the webhook once and reuse it for multiple sends
- Include Meaningful Titles - The
titlefield is required and shown prominently - Structure Data Consistently - Use consistent field names in your
dataobject - Handle Errors Gracefully - Wrap sends in try-catch and handle failures
- Monitor Usage - Check your usage in the dashboard to avoid hitting limits
- Use Unique Payloads - Add timestamps to avoid duplicate detection if resending
- Regenerate Secrets Periodically - Rotate webhook secrets for security
Troubleshooting
Notification Not Delivered
- Check service executions in the dashboard for error messages
- Verify service configuration (email addresses, Slack channels)
- Ensure you haven't exceeded usage limits
- Check if the service shows as
skippedorerror
Invalid Signature Error
- Verify you're using the correct webhook secret
- Check that the signature timestamp is within 5 minutes
- Ensure the payload hasn't been modified after signing
- If using the SDK, ensure your API key is valid
Duplicate Request Rejected
- Identical payloads within 5 minutes are blocked
- Add a timestamp or unique ID to your
dataobject - Wait 5 minutes before resending the same payload
Rate Limited
- Check response headers for
X-RateLimit-*values - Implement backoff based on
Retry-Afterheader - Spread requests over time for batch operations
Next Steps
- Learn about Security Best Practices
- Explore the SDK Reference
- Check out API Reference for REST API details
- Review Examples for common use cases