Receive real-time notifications when project generation is complete.
Overview
Webhooks provide instant notifications when your projects finish generating, eliminating the need for constant polling. When you include a webhookUrl in your project creation request, InitRepo will send a POST request to that URL when generation completes.
Setup
Include a webhookUrl in your project creation request:
{
"projectIdea": "Build a task management app",
"projectType": "web",
"webhookUrl": "https://your-app.com/webhooks/initrepo"
}
Webhook Payload
{
"event": "project.completed",
"timestamp": "2024-01-15T10:45:00Z",
"data": {
"projectId": "550e8400-e29b-41d4-a716-446655440000",
"project": {
"name": "TaskFlow App",
"status": "completed",
"creditsConsumed": 15000,
"createdAt": "2024-01-15T10:30:00Z",
"completedAt": "2024-01-15T10:45:00Z"
}
}
}
Content-Type: application/json
X-InitRepo-Event: project.completed
User-Agent: InitRepo-Webhooks/1.0
X-InitRepo-Signature: sha256=abc123def456...
X-InitRepo-Timestamp: 1699123456
X-Request-ID: req_1234567890
API-Version: v1.0
Payload Fields
Always “project.completed” for completion notifications.
ISO 8601 timestamp when the webhook was sent.
Unique identifier of the completed project.
Always “completed” for success notifications.
data.project.creditsConsumed
Total credits consumed for this project.
ISO 8601 timestamp when the project was created.
ISO 8601 timestamp when the project completed.
Security Requirements
HTTPS Only
- Webhook URLs must use HTTPS protocol
- HTTP URLs will be rejected during project creation
- TLS 1.2 or higher required
No Private IPs
- Private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) are blocked
- Localhost addresses (127.0.0.0/8) are not allowed
- Link-local addresses (169.254.0.0/16) are blocked
Webhook Signature Verification (Required)
InitRepo signs all webhook payloads with HMAC-SHA256 using your webhook secret. Always verify signatures to ensure authenticity.
Security NoticeWebhook signature verification is required for security. Unsigned webhooks should be rejected to prevent spoofing attacks.
Getting Your Webhook Secret
Your webhook secret is available in your InitRepo dashboard under API Keys. Each API key has its own unique webhook secret.
Signature Verification Process
import crypto from 'crypto';
function verifyWebhookSignature(payload, signature, secret) {
// Create HMAC hash of the payload
const hmac = crypto.createHmac('sha256', secret);
hmac.update(payload, 'utf8');
const expectedSignature = `sha256=${hmac.digest('hex')}`;
// Use timingSafeEqual to prevent timing attacks
const sigBuffer = Buffer.from(signature, 'utf8');
const expectedBuffer = Buffer.from(expectedSignature, 'utf8');
return sigBuffer.length === expectedBuffer.length &&
crypto.timingSafeEqual(sigBuffer, expectedBuffer);
}
// Example webhook handler with signature verification
app.post('/webhooks/initrepo', (req, res) => {
const signature = req.headers['x-initrepo-signature'];
const payload = JSON.stringify(req.body);
const secret = process.env.INITREPO_WEBHOOK_SECRET;
// Verify signature
if (!verifyWebhookSignature(payload, signature, secret)) {
console.error('Invalid webhook signature');
return res.status(401).json({ error: 'Invalid signature' });
}
const { event, data } = req.body;
// Validate event type
if (event !== 'project.completed') {
return res.status(400).json({ error: 'Invalid event type' });
}
// Process the webhook
console.log('Project completed:', data.projectId);
res.status(200).json({ received: true });
});
Python Example
import hmac
import hashlib
def verify_webhook_signature(payload, signature, secret):
"""Verify webhook signature using HMAC-SHA256"""
expected = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
expected_sig = f"sha256={expected}"
return hmac.compare_digest(expected_sig, signature)
@app.route('/webhooks/initrepo', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-InitRepo-Signature')
payload = request.get_data(as_text=True)
secret = os.environ['INITREPO_WEBHOOK_SECRET']
if not verify_webhook_signature(payload, signature, secret):
return jsonify({'error': 'Invalid signature'}), 401
data = request.json
# Process webhook...
return jsonify({'received': True}), 200
Additional Security Measures
Rate Limiting Protection
- Implement rate limiting on your webhook endpoints
- InitRepo includes automatic retry protection against abuse
- Maximum 6 delivery attempts per webhook with exponential backoff
Request Validation
app.post('/webhooks/initrepo', (req, res) => {
// Verify content type
if (req.headers['content-type'] !== 'application/json') {
return res.status(400).json({ error: 'Invalid content type' });
}
// Verify user agent
const userAgent = req.headers['user-agent'];
if (!userAgent || !userAgent.startsWith('InitRepo-Webhooks/')) {
return res.status(400).json({ error: 'Invalid user agent' });
}
// Verify timestamp (prevent replay attacks)
const timestamp = parseInt(req.headers['x-initrepo-timestamp']);
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - timestamp) > 300) { // 5 minute tolerance
return res.status(400).json({ error: 'Request too old' });
}
// Continue with signature verification...
});
Error Handling
Enhanced Retry Logic
InitRepo uses an intelligent retry system with exponential backoff and jitter to handle failed webhook deliveries:
Retry Schedule
- Attempt 1: Immediate delivery
- Attempt 2: 1 second + random jitter (0-500ms)
- Attempt 3: 2 seconds + random jitter (0-1s)
- Attempt 4: 4 seconds + random jitter (0-2s)
- Attempt 5: 8 seconds + random jitter (0-4s)
- Attempt 6: 16 seconds + random jitter (0-8s) - Final attempt
What Triggers Retries
- HTTP status codes other than 2xx (200-299)
- Network timeouts (>10 seconds)
- Connection refused or DNS resolution failures
- SSL/TLS handshake failures
Delivery Status Tracking
Each webhook attempt is logged with detailed status information available through the API:
{
"webhookId": "wh_1234567890",
"url": "https://your-app.com/webhooks/initrepo",
"attempts": [
{
"attemptNumber": 1,
"timestamp": "2024-01-15T10:45:00Z",
"status": "failed",
"httpStatus": 500,
"responseTime": 2.5,
"error": "Internal Server Error"
},
{
"attemptNumber": 2,
"timestamp": "2024-01-15T10:45:01Z",
"status": "success",
"httpStatus": 200,
"responseTime": 0.8
}
],
"finalStatus": "delivered"
}
Webhook Monitoring
Access comprehensive delivery statistics through the API:
// Get webhook delivery stats for a project
const response = await fetch(`https://api.initrepo.com/v1/projects/${projectId}/webhooks`, {
headers: {
'Authorization': 'Bearer ir_live_your_api_key'
}
});
const { webhookDeliveries } = await response.json();
Timeout Configuration
- Connection Timeout: 5 seconds to establish connection
- Response Timeout: 10 seconds to receive complete response
- Total Request Timeout: 15 seconds maximum per attempt
Response Requirements
- Success: Return HTTP status 200-299 to acknowledge receipt
- Failure: Any other status code triggers retry according to schedule
- Response Body: Ignored (can be empty or JSON)
- Response Time: Aim for <5 seconds to avoid timeouts
Error Scenarios
Permanent Failures (No Retries)
- URL returns 404 Not Found
- Invalid HTTPS certificate
- Webhook URL blocked by security policy
Temporary Failures (Will Retry)
- 5xx server errors
- Network timeouts
- Rate limiting (429 status)
- Connection refused
Best Practices
Idempotency
// Implement idempotency to handle duplicate webhooks
const processedWebhooks = new Set();
app.post('/webhooks/initrepo', (req, res) => {
const { data } = req.body;
const projectId = data.projectId;
if (processedWebhooks.has(projectId)) {
return res.status(200).json({ message: 'Already processed' });
}
// Process webhook
processedWebhooks.add(projectId);
res.status(200).json({ received: true });
});
Logging and Monitoring
// Log all webhook attempts
app.post('/webhooks/initrepo', (req, res) => {
const timestamp = new Date().toISOString();
const { event, data } = req.body;
console.log(`[${timestamp}] Webhook received: ${event} for project ${data.projectId}`);
// Process webhook...
res.status(200).json({ received: true });
});
Rate Limiting
- Implement rate limiting on your webhook endpoint
- Expect up to 5 webhook attempts per project completion
- Handle bursts gracefully
Testing Webhooks
Local Development
Use tools like ngrok or localtunnel to expose local servers:
# Using ngrok
ngrok http 3000
# Forwarding: https://abc123.ngrok.io -> http://localhost:3000
# Update webhook URL in request
{
"webhookUrl": "https://abc123.ngrok.io/webhooks/initrepo"
}
Test Mode
Use test API keys for development - webhooks work the same way but don’t consume credits.
Troubleshooting
Webhook Not Received
- Check URL: Ensure webhook URL is HTTPS and publicly accessible
- Verify Logs: Check your application logs for incoming requests
- Test Endpoint: Send a test POST request to your webhook URL
- Check Firewall: Ensure your server accepts POST requests on the webhook path
Duplicate Webhooks
- Implement Idempotency: Use project IDs to prevent duplicate processing
- Check Timestamps: Compare webhook timestamps to avoid processing old events
- Log Processing: Keep track of processed webhook events
Timeout Issues
- Optimize Response Time: Ensure your webhook handler responds within 10 seconds
- Async Processing: Move heavy processing to background jobs
- Return Early: Send 200 response immediately, process asynchronously