Skip to main content
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:

AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 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.