Webhook Integration Guide
Everything you need to connect your application to real-time event notifications from the Taskee Portal API β from setup to production-grade reliability.
What are Webhooks?
Webhooks are a way for applications to communicate in real-time. Think of them as automatic notifications that are sent to your application when something happens in our platform β no polling required.
Real-World Example
Imagine you're building a task management or e-commerce app integrated with Taskee:
- β When a customer places an order β you get a webhook notification
- β When the order status changes β you get another webhook notification
- β When the payment is processed β you get yet another notification
This way, your app stays updated without constantly asking "has anything changed?"
Getting Started
Step 1: Create Your Webhook Endpoint
First, you need a public URL that can receive webhook notifications. Choose one of the following options:
Cloud Service
- Heroku β Deploy a simple web app
- AWS Lambda β Serverless function
- Google Cloud Functions β Serverless function
- Vercel β Easy deployment platform
Testing Services
- webhook.site β Temporary URL for testing
- ngrok β Expose local server to the internet
Your Own Server
- Deploy a web application on your server
- Ensure it's accessible via HTTPS
Step 2: Create a Simple Webhook Handler
Here's a basic example using Node.js and Express:
const express = require('express')
const app = express()
// Parse JSON requests
app.use(express.json())
// Your webhook endpoint
app.post('/webhooks', (req, res) => {
console.log('Received webhook:', req.body)
const eventType = req.body.type
const eventData = req.body.data
switch (eventType) {
case 'ContactCreate':
console.log('New contact created:', eventData)
break
case 'ContactUpdate':
console.log('Contact updated:', eventData)
break
default:
console.log('Unknown event type:', eventType)
}
// Always respond with 200 OK
res.status(200).json({ success: true })
})
const PORT = process.env.PORT || 3000
app.listen(PORT, () => {
console.log(`Webhook server running on port ${PORT}`)
})
Step 3: Test Your Endpoint
Before connecting to the Taskee Portal API, test your endpoint with a curl request:
curl -X POST https://your-app.com/webhooks \
-H "Content-Type: application/json" \
-d '{
"type": "ContactCreate",
"timestamp": "2025-01-28T14:35:00.000Z",
"webhookId": "test-123",
"data": {
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]"
}
}'
Available Webhook Events
Taskee Portal API offers a comprehensive set of webhook events that cover all major activities in our platform.
Event Categories
For complete payload structures, field descriptions, data types, and sample JSON responses for every event, refer to the full Taskee Portal API Webhook Reference documentation.
Security: Verifying Webhook Authenticity
Why Verification is Important
Webhooks can be spoofed by malicious actors. Always verify that webhooks are coming from the Taskee Portal API before processing them.
How to Verify
We use a private key to sign our webhook payloads. You can verify the signature using our public key. Each request includes a digital signature in the x-wh-signature header.
Taskee Portal API Public Key
-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAokvo/r9tVgcfZ5DysOSC Frm602qYV0MaAiNnX9O8KxMbiyRKWeL9JpCpVpt4XHIcBOK4u3cLSqJGOLaPuXw6 dO0t6Q/ZVdAV5Phz+ZtzPL16iCGeK9po6D6JHBpbi989mmzMryUnQJezlYJ3DVfB csedpinheNnyYeFXolrJvcsjDtfAeRx5ByHQmTnSdFUzuAnC9/GepgLT9SM4nCpv uxmZMxrJt5Rw+VUaQ9B8JSvbMPpez4peKaJPZHBbU3OdeCVx5klVXXZQGNHOs8gF 3kvoV5rTnXV0IknLBXlcKKAQLZcY/Q9rG6Ifi9c+5vqlvHPCUJFT5XUGG5RKgOKU J062fRtN+rLYZUV+BjafxQauvC8wSWeYja63VSUruvmNj8xkx2zE/Juc+yjLjTXp IocmaiFeAO6fUtNjDeFVkhf5LNb59vECyrHD2SQIrhgXpO4Q3dVNA5rw576PwTzN h/AMfHKIjE4xQA1SZuYJmNnmVZLIZBlQAF9Ntd03rfadZ+yDiOXCCs9FkHibELhC HULgCsnuDJHcrGNd5/Ddm5hxGQ0ASitgHeMZ0kcIOwKDOzOU53lDza6/Y09T7sYJ PQe7z0cvj7aE4B+Ax1ZoZGPzpJlZtGXCsu9aTEGEnKzmsFqwcSsnw3JB31IGKAyk T1hhTiaCeIY/OwwwNUY2yvcCAwEAAQ== -----END PUBLIC KEY-----
Here's how to verify the x-wh-signature in Node.js:
const crypto = require('crypto')
const publicKey = `<use_the_above_key>`
function verifySignature(payload, signature) {
const verifier = crypto.createVerify('SHA256')
verifier.update(payload)
verifier.end()
return verifier.verify(publicKey, signature, 'base64')
}
// Example usage
const payload = JSON.stringify({
"timestamp": "2025-01-28T14:35:00Z",
"webhookId": "abc123xyz",
// ...other webhook data
})
const signature = "<received-x-wh-signature>"
const isValid = verifySignature(payload, signature)
return isValid
Setting Up Your Integration
Create Your OAuth Application
Create an OAuth application via the Taskee Portal API dashboard. This gives you a webhook URL to receive notifications, access to specific data based on scopes, and the ability to subscribe to specific events.
Configure Your Webhook URL
After filling in all mandatory information, navigate to the Auth section under Advanced Settings. Select the scope of your application from the dropdown menu.
Choose Your Events
After defining the scopes, go to the Webhook section under Advanced Settings. Toggle on and paste your webhook URL against the events you wish to receive notifications for.
Handling Webhooks Reliably
Best Practices
-
Always Respond Quickly Process webhooks asynchronously if needed. Return
200 OKimmediately and do heavy processing in the background. -
Handle Duplicates Store webhook IDs to prevent duplicate processing. Make your processing idempotent β safe to run multiple times with the same result.
-
Log Everything Log all incoming webhooks, processing results, and errors for debugging. Good observability is essential for production reliability.
Example Implementation
const express = require('express')
const crypto = require('crypto')
const app = express()
app.use(express.json())
// Store processed webhook IDs (use a database in production)
const processedWebhooks = new Set()
app.post('/webhooks', async (req, res) => {
try {
// 1. Verify signature
const signature = req.headers['x-wh-signature']
if (!verifyWebhookSignature(req.body, signature)) {
return res.status(401).json({ error: 'Invalid signature' })
}
// 2. Check for duplicates
if (processedWebhooks.has(req.body.webhookId)) {
return res.status(200).json({ message: 'Already processed' })
}
// 3. Log the webhook
console.log('Processing webhook:', req.body.type, req.body.webhookId)
// 4. Process asynchronously (don't block the response)
setImmediate(() => { processWebhookAsync(req.body) })
// 5. Mark as processed
processedWebhooks.add(req.body.webhookId)
// 6. Respond immediately
res.status(200).json({ success: true })
} catch (error) {
console.error('Webhook processing error:', error)
res.status(200).json({ success: false, error: 'Processing failed' })
}
})
async function processWebhookAsync(webhook) {
try {
switch (webhook.type) {
case 'ContactCreate': await handleNewContact(webhook.data); break
case 'ContactUpdate': await handleContactUpdate(webhook.data); break
}
} catch (error) {
console.error('Failed to process webhook:', webhook.webhookId, error)
}
}
Error Handling & Retries
How Our Retry System Works
We only retry webhook deliveries when your endpoint returns a 429 status code. All other failure types are not retried.
| Parameter | Value |
|---|---|
| Retry Trigger | 429 Rate limit only |
| Retry Interval | 10 minutes between attempts + jitter |
| Max Retries | 6 attempts for 429 errors |
| Total Duration | ~1 hour 10 minutes (6 Γ 10 min + initial + jitter) |
| Retry Condition | Only continues if 429 status codes keep coming back |
| Scheduling | Distributed scheduling with random jitter |
Understanding Jitter
What is jitter? Jitter is a random delay added to retry attempts to prevent the "thundering herd" problem. When multiple webhooks fail with 429 status codes simultaneously, without jitter they would all retry at the same time β potentially overwhelming your server again.
Our distributed scheduling system applies random jitter to each retry attempt. The jitter can vary significantly β from seconds to minutes β ensuring a natural distribution that spreads retry load over time.
What You Should Do
Return 200 for success:
res.status(200).json({ success: true })
Return 200 even for processing errors β to acknowledge receipt:
try {
await processWebhook(req.body)
res.status(200).json({ success: true })
} catch (error) {
console.error('Processing failed:', error)
// Still return 200 to acknowledge receipt
res.status(200).json({ success: false, error: 'Processing failed' })
}
Only return error codes for real infrastructure issues:
| Status | Meaning |
|---|---|
| 408 | Your server is too slow to respond |
| 429 | You're receiving too many requests (triggers retry) |
| 5xx | Your server is down or broken (no retry) |
Testing Your Integration
The best way to verify your webhook integration is to use the Webhook Logs Dashboard. This dashboard provides comprehensive monitoring and troubleshooting for all webhook deliveries to your application.
The Webhook Logs Dashboard allows you to:
- View all webhook events sent to your application and track success/failure rates
- Search for specific webhook IDs, filter by event type and status codes
- View detailed payload information and monitor retry attempts
- Investigate delivery issues in real-time
Accessing the Dashboard
Navigate to your Application Dashboard
Select the app you want to check logs for
Go to Insights from the left menu
Click on Logs β the Webhooks tab will be active by default
Common Issues & Solutions
setImmediate or a queue, and respond with 200 OK as quickly as possible.