Webhooks
Integrate PromptReports with your external systems using webhooks. Receive real-time notifications when prompts are created, updated, evaluated, or promoted.
What are Webhooks?#
Webhooks are HTTP callbacks that send real-time notifications to your systems when events occur in PromptReports. Instead of polling for changes, your application receives instant updates when prompts are modified, versions are promoted, or evaluations complete.
Real-Time Updates
Receive instant notifications without polling or delays.
Secure Delivery
HMAC signatures ensure payloads are authentic and unmodified.
Automatic Retry
Failed deliveries are automatically retried with exponential backoff.
Delivery History
Track all webhook deliveries with status codes and responses.
Creating Webhooks#
You can create webhooks at the folder level or globally for your account:
Navigate to Webhooks
Click "Create Webhook"
Configure the webhook
- Name: A descriptive name for this webhook
- URL: The HTTPS endpoint to receive events
- Events: Which events should trigger this webhook
- Secret: Optional secret for HMAC signature verification
Test the webhook
HTTPS Required
Event Types#
Subscribe to the events that matter for your integration:
| Event | Description | Triggered When |
|---|---|---|
| prompt.created | New prompt created | A new prompt is added to a folder |
| prompt.updated | Prompt content modified | Draft changes are saved |
| version.created | New version saved | A version is saved from draft |
| version.promoted | Version promoted to new stage | Version moves to staging/production |
| evaluation.started | Evaluation begun | A batch evaluation starts running |
| evaluation.completed | Evaluation finished | Evaluation completes with results |
| approval.requested | Approval requested | Someone requests promotion approval |
| approval.completed | Approval decision made | Approver accepts or rejects request |
Payload Structure#
All webhook payloads follow a consistent structure:
{
"id": "wh_evt_abc123",
"type": "version.promoted",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"promptId": "prm_xyz789",
"promptName": "Customer Support Response",
"versionId": "ver_def456",
"versionNumber": 5,
"previousStage": "staging",
"newStage": "production",
"promotedBy": {
"id": "usr_ghi012",
"name": "Jane Smith",
"email": "jane@example.com"
}
},
"metadata": {
"folderId": "fld_jkl345",
"folderName": "Production Prompts"
}
}| Field | Type | Description |
|---|---|---|
| id | string | Unique event identifier (for deduplication) |
| type | string | Event type (e.g., "version.promoted") |
| timestamp | string | ISO 8601 timestamp of when event occurred |
| data | object | Event-specific data payload |
| metadata | object | Additional context (folder info, etc.) |
Signature Verification#
When you provide a secret, PromptReports signs each payload using HMAC-SHA256. Always verify signatures to ensure payloads are authentic.
import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
secret: string
): boolean {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook handler:
app.post('/webhook', (req, res) => {
const signature = req.headers['x-promptreports-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the webhook...
res.status(200).json({ received: true });
});Timing-Safe Comparison
Testing Webhooks#
Test your webhook integration before going live:
Use the Test button
Check delivery history
Inspect payloads
Use a tunnel for local development
Best Practices#
Always Verify Signatures
Never trust webhook payloads without verifying the HMAC signature.
Respond Quickly
Return 2xx within 30 seconds. Process heavy work asynchronously.
Handle Duplicates
Use the event ID for idempotency—events may be delivered more than once.
Handle Failures Gracefully
Return 4xx for client errors, 5xx for server errors. We'll retry 5xx.