Webhooks enable real-time notifications from MindPeeker to your application when specific events occur. Instead of continuously polling the API for status updates, you can receive instant notifications when sessions complete, analyses finish, or other important events happen.
session.created - New session initiatedsession.started - Session processing begansession.completed - Session finished successfullysession.failed - Session failed or was cancelledsession.progress_updated - Session progress updated (every 10%)analysis.created - New analysis queuedanalysis.started - Analysis processing begananalysis.completed - Analysis completed successfullyanalysis.failed - Analysis faileddowsing.query_created - New dowsing query submitteddowsing.query_completed - Dowsing query completeddowsing.query_failed - Dowsing query failedaccount.subscription_updated - Subscription plan changedaccount.usage_threshold_reached - Usage limit approachingaccount.payment_succeeded - Payment processed successfullyaccount.payment_failed - Payment failedsystem.maintenance_scheduled - Scheduled maintenance announcedsystem.service_disruption - Service disruption detectedsystem.security_alert - Security-related notificationCreate an HTTPS endpoint in your application that can receive POST requests:
// Express.js example
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.raw({ type: 'application/json' }));
app.post('/webhook', (req, res) => {
const signature = req.headers['x-mindpeeker-signature'];
const payload = req.body;
// Verify webhook signature (recommended)
const expectedSignature = crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if (signature !== `sha256=${expectedSignature}`) {
return res.status(401).send('Invalid signature');
}
try {
const event = JSON.parse(payload);
// Handle different event types
switch (event.type) {
case 'session.completed':
handleSessionCompleted(event.data);
break;
case 'analysis.completed':
handleAnalysisCompleted(event.data);
break;
// ... other event types
}
res.status(200).send('OK');
} catch (error) {
console.error('Webhook processing error:', error);
res.status(500).send('Internal server error');
}
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
Register your webhook endpoint through the API or dashboard:
curl -X POST https://api.mindpeeker.com/v1/webhooks \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhook",
"events": [
"session.completed",
"analysis.completed",
"dowsing.query_completed"
],
"secret": "your_webhook_secret_here",
"active": true
}'
Test your webhook configuration:
curl -X POST https://api.mindpeeker.com/v1/webhooks/{webhook_id}/test \
-H "Authorization: Bearer your_api_key"
All webhook events follow this structure:
{
"id": "evt_1234567890abcdef",
"type": "session.completed",
"created_at": "2025-01-15T10:30:00Z",
"data": {
"session_id": "sess_123456789",
"status": "completed",
"confidence_score": 0.87,
"completed_at": "2025-01-15T10:30:00Z"
},
"livemode": true,
"pending_webhooks": 0
}
{
"type": "session.completed",
"data": {
"session_id": "sess_123456789",
"type": "remote_viewing",
"target": "Missing person investigation",
"status": "completed",
"confidence_score": 0.87,
"duration_minutes": 28,
"results": {
"coordinates": {
"latitude": 40.7128,
"longitude": -74.0060
},
"descriptors": ["urban environment", "water body nearby"],
"sketches": ["https://cdn.mindpeeker.com/sketches/sess_123456789_1.png"]
},
"completed_at": "2025-01-15T10:30:00Z"
}
}
{
"type": "analysis.completed",
"data": {
"analysis_id": "anal_123456789",
"target_type": "location",
"status": "completed",
"confidence_score": 0.91,
"results": {
"summary": "Analysis reveals structural anomalies...",
"key_findings": [
"Structural anomalies detected",
"Temporal inconsistencies present"
],
"risk_assessment": {
"level": "medium",
"factors": ["temporal_instability"]
}
},
"processing_time": "45 minutes",
"completed_at": "2025-01-15T11:15:00Z"
}
}
{
"type": "dowsing.query_completed",
"data": {
"query_id": "dowse_123456789",
"query_type": "location",
"question": "Find optimal location for water well",
"answer": "positive",
"confidence": 0.89,
"coordinates": {
"latitude": 40.7132,
"longitude": -74.0058,
"accuracy_meters": 15
},
"chart_data": {
"chart_type": "radar",
"readings": [0.8, 0.6, 0.9, 0.7],
"interpretation": "Strong positive response"
},
"completed_at": "2025-01-15T09:45:00Z"
}
}
All webhook requests are signed with HMAC-SHA256 using your webhook secret:
import hmac
import hashlib
def verify_webhook_signature(payload, signature, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(
f'sha256={expected_signature}',
signature
)
signature = request.headers.get('X-MindPeeker-Signature')
payload = request.body
if verify_webhook_signature(payload, signature, 'your_webhook_secret'):
# Process webhook
pass
else:
# Reject webhook
pass
For additional security, you can whitelist MindPeeker's webhook IP addresses:
52.52.52.52
52.53.53.53
Respond to webhook requests quickly (within 5 seconds):
// Acknowledge immediately, process asynchronously
app.post('/webhook', (req, res) => {
// Quick validation
if (!verifySignature(req.body, req.headers['x-mindpeeker-signature'])) {
return res.status(401).send('Invalid signature');
}
// Acknowledge immediately
res.status(200).send('OK');
// Process asynchronously
setImmediate(() => {
processWebhook(req.body);
});
});
Handle duplicate webhook deliveries:
const processedEvents = new Set();
function processWebhook(event) {
if (processedEvents.has(event.id)) {
console.log('Duplicate event, skipping');
return;
}
processedEvents.add(event.id);
// Process event
handleEvent(event);
}
Implement robust error handling:
async function handleSessionCompleted(data) {
try {
const session = await updateSessionInDatabase(data.session_id, data);
if (data.confidence_score > 0.8) {
await notifyHighConfidenceResult(session);
}
} catch (error) {
console.error('Error handling session completion:', error);
// Retry logic or alert monitoring
await alertMonitoringSystem(error);
}
}
Monitor webhook delivery and processing:
// Log all incoming webhooks
app.post('/webhook', (req, res) => {
console.log('Webhook received:', {
type: req.body.type,
id: req.body.id,
timestamp: new Date().toISOString()
});
// ... processing logic
});
// Monitor webhook health
setInterval(async () => {
const stats = await getWebhookStats();
console.log('Webhook stats:', stats);
}, 60000); // Every minute
MindPeeker automatically retries failed webhook deliveries:
| Attempt | Delay | Max Duration |
|---|---|---|
| 1 | Immediate | - |
| 2 | 5 seconds | 5 seconds |
| 3 | 30 seconds | 35 seconds |
| 4 | 2 minutes | 2 minutes 35 seconds |
| 5 | 10 minutes | 12 minutes 35 seconds |
| 6 | 30 minutes | 42 minutes 35 seconds |
| 7 | 1 hour | 1 hour 42 minutes 35 seconds |
If all retries fail, the webhook is marked as failed and you'll receive a webhook.failed event.
curl -X GET https://api.mindpeeker.com/v1/webhooks \
-H "Authorization: Bearer your_api_key"
curl -X PATCH https://api.mindpeeker.com/v1/webhooks/{webhook_id} \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"events": ["session.completed", "analysis.completed"],
"active": true
}'
curl -X DELETE https://api.mindpeeker.com/v1/webhooks/{webhook_id} \
-H "Authorization: Bearer your_api_key"
Use tools like ngrok to test webhooks locally:
ngrok http 3000
curl -X POST https://api.mindpeeker.com/v1/webhooks \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"url": "https://abc123.ngrok.io/webhook",
"events": ["session.completed"],
"secret": "test_secret"
}'
Send test events to your webhook:
curl -X POST https://api.mindpeeker.com/v1/webhooks/{webhook_id}/test \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"event_type": "session.completed",
"test_data": {
"session_id": "test_session_123",
"confidence_score": 0.85
}
}'
All official SDKs provide webhook utilities:
from mindpeeker.webhooks import WebhookHandler
handler = WebhookHandler('your_webhook_secret')
@handler.on('session.completed')
def handle_session_completed(event):
print(f"Session {event.data.session_id} completed")
@app.route('/webhook', methods=['POST'])
def webhook():
event = handler.construct_event(request.data, request.headers['X-MindPeeker-Signature'])
handler.process_event(event)
return 'OK'
import { WebhookHandler } from '@mindpeeker/javascript';
const handler = new WebhookHandler('your_webhook_secret');
handler.on('session.completed', (event) => {
console.log(`Session ${event.data.session_id} completed`);
});
// In Express
app.post('/webhook', (req, res) => {
const event = handler.constructEvent(req.body, req.headers['x-mindpeeker-signature']);
handler.processEvent(event);
res.status(200).send('OK');
});
Enable debug mode for detailed logging:
const handler = new WebhookHandler('your_webhook_secret', {
debug: true,
logLevel: 'verbose'
});
Monitor webhook delivery in your MindPeeker dashboard:
For webhook support: