Navigation
reference
Webhook Events
Configuring Webhooks
Prospector can send HTTP POST requests to your endpoints when specific events occur. Configure webhooks in the dashboard under Prospector > Settings > Webhooks or through the API.
# Register a webhook via CLI
ghoststack prospector webhooks add \
--url "https://your-server.com/hooks/prospector" \
--events "lead.scored,proposal.submitted,contract.started" \
--secret "whsec_your_signing_secret"
Each webhook registration includes a URL, a list of event types to subscribe to, and an optional signing secret for payload verification.
Payload Format
All webhook payloads share a common envelope:
{
"id": "evt_9k3m2f8a",
"type": "lead.scored",
"created_at": "2026-04-20T14:30:00Z",
"data": {
// Event-specific payload
}
}
The Content-Type header is always application/json. Payloads are sent as HTTP POST requests with a maximum body size of 256 KB.
Signature Verification
If you provide a signing secret when registering a webhook, Prospector includes an X-GhostStack-Signature header with each delivery. The signature is an HMAC-SHA256 hash of the raw request body using your signing secret.
import { createHmac } from 'crypto';
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const expected = createHmac('sha256', secret).update(body).digest('hex');
return signature === `sha256=${expected}`;
}
Always verify signatures before processing webhook payloads. Without verification, an attacker could send forged events to your endpoint.
Event Types
Lead Events
lead.discovered - A new lead was found during a scan but has not been scored yet.
{
"id": "evt_...",
"type": "lead.discovered",
"data": {
"lead_id": "lead_3f8k2m",
"platform": "upwork",
"job_title": "React Native App Development",
"job_url": "https://upwork.com/jobs/..."
}
}
lead.scored - A lead has been scored. Includes the full score breakdown.
{
"id": "evt_...",
"type": "lead.scored",
"data": {
"lead_id": "lead_3f8k2m",
"score": {
"composite": 82,
"confidence": 0.87,
"signals": {
"skill_match": 90,
"budget": 75,
"client_history": 88,
"competition": 70,
"timeline": 80
}
}
}
}
lead.excluded - A lead was filtered out by the rules engine.
{
"id": "evt_...",
"type": "lead.excluded",
"data": {
"lead_id": "lead_3f8k2m",
"rule": "exclude-low-budget",
"reason": "job.budget.amount (200) < 500"
}
}
Proposal Events
proposal.drafted - An AI draft has been generated and is awaiting review.
proposal.submitted - A proposal was submitted to the platform.
proposal.failed - Proposal submission failed (rate limit, posting closed, etc.).
{
"id": "evt_...",
"type": "proposal.failed",
"data": {
"proposal_id": "prop_2m9k3f",
"lead_id": "lead_3f8k2m",
"error": {
"code": "posting_closed",
"message": "The job posting is no longer accepting proposals"
}
}
}
Contract Events
contract.started - You won a contract. Includes contract terms.
contract.milestone_due - A milestone deadline is approaching (sent at 48h and 24h).
contract.milestone_approved - A submitted milestone was approved by the client.
contract.completed - The contract has been marked as complete.
contract.invoice_prompt - A billing period ended or milestone was approved, prompting invoice creation.
Delivery and Retries
Prospector expects your endpoint to return a 2xx status code within 10 seconds. If the request times out or returns a non-2xx status, Prospector retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 30 seconds |
| 3 | 2 minutes |
| 4 | 10 minutes |
| 5 | 1 hour |
After 5 failed attempts, the event is marked as failed and no further retries are attempted. Failed events are visible in the dashboard under Webhooks > Delivery Log, where you can manually retry them.
Testing Webhooks
Use the CLI to send test events to your endpoint without triggering real platform actions:
# Send a test lead.scored event
ghoststack prospector webhooks test \
--url "https://your-server.com/hooks/prospector" \
--event "lead.scored"
Test events include a "test": true field in the payload so your handler can distinguish them from real events.