Webhooks
Receive real-time notifications when events occur in your PlanningForge organization or teams.
What are Webhooks?
Webhooks allow you to build integrations that subscribe to certain events on PlanningForge. When an event is triggered, we send an HTTP POST request to the webhook's configured URL.
Use webhooks to integrate PlanningForge with your own systems, trigger notifications, update project management tools, or build custom automations.
Table of Contents
Getting Started
Prerequisites
Before You Begin
- Organization or Team Owner permissions - You need admin access to configure webhooks
- A webhook endpoint - A publicly accessible URL that can receive POST requests
- HTTPS support - Your endpoint must support HTTPS (recommended)
- Ability to verify signatures - Your endpoint should validate webhook signatures for security
Best Practices
- • Always verify webhook signatures to ensure authenticity
- • Respond quickly (within 5 seconds) to avoid timeouts
- • Process webhooks asynchronously to prevent delays
- • Return 2xx status code to acknowledge receipt
- • Use HTTPS endpoints for secure communication
Creating Your First Webhook
Organization-Level Webhooks
- Navigate to Organization Settings from the main menu
- Click on the Webhooks tab
- Click Create Webhook button
- Enter your webhook URL (e.g.,
https://api.yourapp.com/webhooks) - Select the events you want to subscribe to
- Optionally add a description for easy identification
- Click Create
- Important: Copy and save the webhook secret - it's only shown once!
Team-Level Webhooks
- Go to your Team Dashboard
- Click Manage Team Webhooks in the Webhook Integrations section
- Follow the same steps as organization webhooks above
- Team webhooks receive events specific to that team only
Save Your Secret!
The webhook secret is only displayed once when you create the webhook. Store it securely - you'll need it to verify webhook signatures. If you lose it, you'll need to create a new webhook.
Webhook Validation
Why Validation?
When you create a webhook, PlanningForge sends a validation challenge to verify you control the endpoint. Your webhook stays in pending status until it responds correctly to this challenge.
How It Works
PlanningForge Sends Challenge
We send a POST request to your endpoint with:
{
"type": "validation",
"challenge": "a1b2c3d4e5f6...",
"webhook_id": "whk_abc123...",
"timestamp": 1730000000
}
Your Endpoint Responds
Echo back the challenge value in JSON format with a 2xx status code:
HTTP/1.1 200 OK
Content-Type: application/json
{
"challenge": "a1b2c3d4e5f6..."
}
Webhook Activated
If the challenge matches, your webhook status changes from pending to active and starts receiving events.
Implementation Examples
PHP/Laravel
Route::post('/webhook', function (Request $request) {
// Handle validation challenge
if ($request->input('type') === 'validation') {
return response()->json([
'challenge' => $request->input('challenge')
]);
}
// Handle actual webhook events...
// (verify signature, process event, etc.)
});
Node.js/Express
app.post('/webhook', (req, res) => {
// Handle validation challenge
if (req.body.type === 'validation') {
return res.status(200).json({
challenge: req.body.challenge
});
}
// Handle actual webhook events...
});
Python/Flask
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.get_json()
# Handle validation challenge
if payload.get('type') == 'validation':
return jsonify({'challenge': payload['challenge']}), 200
# Handle actual webhook events...
Validation Tips
- • Respond within 30 seconds (validation timeout)
- • Return exactly the same challenge value you received
- • Ensure your endpoint is publicly accessible
- • Return a 2xx status code (200, 201, 204, etc.)
- • The response must be valid JSON with a "challenge" field
Available Events
PlanningForge webhooks can be triggered by various events. Choose the events that are relevant to your integration.
Team Events
Available for both team-level and organization-level webhooks:
Planning Sessions
session.started- Session beginssession.completed- Session finishessession.cancelled- Session cancelled
Stories
story.created- New story addedstory.estimated- Final estimate setstory.updated- Story modified
Voting
vote.cast- Individual vote submittedvote.revealed- Votes revealedconsensus.reached- Team consensus
Team Changes
team.member.added- User addedteam.member.removed- User removedteam.updated- Team details changed
Retrospectives
retrospective.started- Retro beginsretrospective.completed- Retro ends
* Only available when retrospectives feature is enabled
Organization-Only Events
These events are only available for organization-level webhooks:
User Management
user.created- New user addeduser.updated- User modifieduser.deleted- User removeduser.role_changed- Role modified
Organization
organization.updated- Org settings changedteam.created- New team createdteam.deleted- Team removed
Security & Verification
Always Verify Signatures!
To ensure webhooks are actually from PlanningForge and not malicious actors, always verify the signature included in every webhook delivery.
How Signatures Work
Every webhook includes a signature in the X-PlanningForge-Signature header. This signature is created using HMAC-SHA256 with your webhook secret.
Example Signature Header:
sha256=a3b5c8d9e1f2a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4
Verification Examples
PHP
function verifyWebhookSignature($payload, $signature, $secret) {
$expectedSignature = 'sha256=' . hash_hmac(
'sha256',
json_encode($payload),
$secret
);
return hash_equals($expectedSignature, $signature);
}
// Usage
$payload = json_decode($request->getContent(), true);
$signature = $request->header('X-PlanningForge-Signature');
$secret = 'your-webhook-secret';
if (!verifyWebhookSignature($payload, $signature, $secret)) {
abort(401, 'Invalid signature');
}
Node.js
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
Python
import hmac
import hashlib
import json
def verify_webhook_signature(payload, signature, secret):
expected_signature = 'sha256=' + hmac.new(
secret.encode('utf-8'),
json.dumps(payload).encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected_signature)
Payload Structure
Headers
Every webhook delivery includes these HTTP headers:
| Header | Description |
|---|---|
X-PlanningForge-Signature |
HMAC-SHA256 signature for verification |
X-PlanningForge-Event |
Event type (e.g., "session.completed") |
X-PlanningForge-Delivery-ID |
Unique delivery identifier |
User-Agent |
PlanningForge-Webhooks/1.0 |
Payload Example
session.completed Event
{
"event": "session.completed",
"webhookable_type": "Team",
"webhookable_id": "team-uuid-here",
"timestamp": "2025-10-25T22:00:00+00:00",
"session": {
"id": "session-uuid",
"name": "Sprint 45 Planning",
"status": "completed",
"started_at": "2025-10-25T20:00:00+00:00",
"completed_at": "2025-10-25T22:00:00+00:00",
"stories_estimated": 15,
"average_estimate": 5.2
},
"team": {
"id": "team-uuid",
"name": "Engineering Team Alpha"
}
}
Reliability & Retries
PlanningForge implements robust retry mechanisms to ensure webhook deliveries are reliable even when endpoints experience temporary issues.
Automatic Retries with Exponential Backoff
If your endpoint fails to respond with a 2xx status code or times out, PlanningForge automatically retries the delivery with increasing delays between attempts:
This exponential backoff strategy gives your endpoint time to recover from temporary issues while minimizing load during outages.
Timeout Settings
Event Delivery Timeout
Your endpoint has 5 seconds to respond to webhook events
Process webhooks asynchronously if you need more time
Validation Timeout
Your endpoint has 30 seconds to respond to validation challenges
Validation happens once when webhook is created
Auto-Deactivation
To protect both systems, webhooks are automatically deactivated after 5 consecutive delivery failures.
To reactivate: Fix the issues on your end, then click the Reactivate button in the webhook management interface.
Delivery History & Monitoring
Every webhook delivery is recorded with complete details:
- Delivery status - Success, failed, or pending
- HTTP status code returned by your endpoint
- Response time in milliseconds
- Error messages if delivery failed
- Full payload for debugging
View delivery history by clicking Logs next to any webhook in the management interface.
Testing Webhooks
Using webhook.site
- Go to webhook.site - you'll get a unique URL
- Copy the unique URL provided
- Create a webhook in PlanningForge using that URL
- Click the Send Test button on your webhook
- View the request details on webhook.site
Testing from Webhook Manager
Once you've created a webhook, you can test it directly from the webhook management interface:
- Navigate to your webhooks in Organization Settings or Team Webhooks
- Find the webhook you want to test
- Click the Test button
- A test payload will be sent to your endpoint
- Check the delivery status in the webhook details
Troubleshooting
Webhook Status: Pending
Note: A webhook stays in "pending" status until it successfully responds to the validation challenge. See the Webhook Validation section for complete details.
Validation Checklist:
- ✓ Endpoint is publicly accessible (not localhost or behind firewall)
- ✓ Endpoint returns 2xx status code (200, 201, 204, etc.)
- ✓ Response is valid JSON with "challenge" field
- ✓ Challenge value matches exactly what was sent
- ✓ Response sent within 30 seconds (validation timeout)
- ✓ Check if
type === 'validation'in your endpoint code
Debugging Steps:
- Check your server logs for incoming POST requests
- Test your endpoint with a tool like Postman or curl
- Verify SSL/TLS certificate is valid (if using HTTPS)
- Try creating a webhook to webhook.site first to see the validation payload
Webhook Status: Failed
Auto-deactivation: Webhooks are automatically deactivated after 5 consecutive delivery failures to protect both systems. See the Reliability & Retries section for details.
Common Causes:
- Endpoint returning errors (4xx or 5xx status codes)
- Response taking too long (timeout: 5 seconds for events, 30s for validation)
- SSL/TLS certificate issues
- Firewall blocking PlanningForge's requests
- Endpoint is down or unreachable
- Signature verification failing (returning 401/403)
Resolution Steps:
- Check your endpoint logs for error details
- Verify endpoint returns 2xx status code for test deliveries
- Ensure response time is under 5 seconds (process asynchronously if needed)
- Test signature verification logic is working correctly
- Verify SSL/TLS certificate is valid and not expired
- Once fixed, click the Reactivate button in webhook management
💡 Pro Tip: Exponential Backoff
PlanningForge retries failed deliveries up to 5 times with increasing delays (60s, 120s, 240s, 480s, 960s). This gives your endpoint time to recover from temporary issues before auto-deactivation occurs.
Not Receiving Webhooks
Checklist:
- Webhook status is Active (not Pending or Failed)
- You've subscribed to the relevant events
- Events are actually being triggered in PlanningForge
- Endpoint URL is correct and publicly accessible
- No firewall rules blocking PlanningForge IPs
- SSL certificate is valid (if using HTTPS)
Need to manage webhooks programmatically?
Our REST API provides full webhook management capabilities including creation, updates, and delivery history.
View API Documentation →