/webhooks

Webhooks

The self-hosted GPT Researcher server can deliver research lifecycle events as outbound HTTP callbacks. Use webhooks when you want to react to long-running research jobs without polling, or when you are running GPT Researcher as a background worker behind your own product.

Streaming alternative: SSE on GET /research/stream.

Registering a webhook

Configure a webhook URL via the WEBHOOK_URL environment variable on your self-hosted server, or pass webhook_url in the body of POST /research.

POST /research HTTP/1.1
Content-Type: application/json

{
  "query": "What are the strategic risks for NVIDIA?",
  "report_type": "research_report",
  "webhook_url": "https://your-app.example.com/hooks/gptr",
  "webhook_secret": "shared-secret-for-hmac-verification"
}

Event types

  • research.startedFired when a /research call accepts a task and begins planning.
  • research.source.foundFired each time a candidate source is discovered.
  • research.source.validatedFired each time a source passes validation and enters the research context.
  • research.report.chunkFired with each chunk of the report as it streams.
  • research.completedFired when a research run finishes; includes report URL and source count.
  • research.failedFired on terminal failure; includes a stable error code and retry guidance.

Payload shape

{
  "id": "evt_01HZ...",
  "type": "research.completed",
  "created_at": "2026-04-30T12:34:56Z",
  "data": {
    "task_id": "task_01HZ...",
    "query": "What are the strategic risks for NVIDIA?",
    "report_url": "https://your-app.example.com/reports/abc",
    "sources": [
      { "url": "...", "title": "..." }
    ],
    "duration_ms": 38123
  }
}

Outbound deliveries set X-GPTR-Event, X-GPTR-Delivery, and X-GPTR-Signature (HMAC-SHA256 of the body using webhook_secret).

Retries and idempotency

  • Retries on non-2xx responses with exponential backoff for up to 24 hours.
  • Each delivery has a unique X-GPTR-Delivery header for dedup.
  • Receivers should respond with 2xx within 5 seconds; long processing should be queued asynchronously on your side.