Skip to content

Webhook Events

Updated Feb 2026

This page documents every webhook event type, its payload structure, and when it fires. Use this as a reference when building your webhook handler.

Payload Structure

All webhook events share this common structure:

json
{
  "success": true,
  "type": "crawl.page",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "metadata": {}
}

Common Fields

FieldTypeDescription
successbooleanWhether the operation succeeded. false on failure events.
typestringThe event type (e.g., crawl.page, extract.completed).
idstringThe job ID (UUID). Use this to correlate events with your original API request.
dataarrayEvent-specific data. Empty for lifecycle events (started, completed), populated for data events (page, action).
metadataobjectCustom metadata you provided in your webhook configuration.
errorstringError message. Only present when success is false.

Crawl Events

crawl.started

Sent when the crawl job begins processing.

json
{
  "success": true,
  "type": "crawl.started",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "metadata": {}
}

crawl.page

Sent for each page scraped during the crawl. The data array contains the page content and metadata.

json
{
  "success": true,
  "type": "crawl.page",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [
    {
      "markdown": "# Page content...",
      "metadata": {
        "title": "Page Title",
        "description": "Page description",
        "url": "https://example.com/page",
        "statusCode": 200,
        "contentType": "text/html",
        "scrapeId": "550e8400-e29b-41d4-a716-446655440001",
        "sourceURL": "https://example.com/page",
        "proxyUsed": "basic",
        "cacheState": "hit",
        "cachedAt": "2025-09-03T21:11:25.636Z",
        "creditsUsed": 1
      }
    }
  ],
  "metadata": {}
}

Data fields for crawl.page:

FieldTypeDescription
markdownstringThe scraped page content in Markdown format.
metadata.titlestringThe page's <title> tag.
metadata.descriptionstringThe page's meta description.
metadata.urlstringFinal URL after any redirects.
metadata.statusCodenumberHTTP status code of the response.
metadata.contentTypestringThe Content-Type header value.
metadata.scrapeIdstringUnique ID for this individual scrape.
metadata.sourceURLstringThe original URL requested.
metadata.proxyUsedstringThe proxy tier used (basic, stealth, etc.).
metadata.cacheStatestringWhether the result was served from cache (hit or miss).
metadata.cachedAtstringISO timestamp of when the cache entry was created.
metadata.creditsUsednumberCredits consumed for this page scrape.

crawl.completed

Sent when the crawl job finishes and all pages have been processed.

json
{
  "success": true,
  "type": "crawl.completed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "metadata": {}
}

Batch Scrape Events

batch_scrape.started

Sent when the batch scrape job begins processing.

json
{
  "success": true,
  "type": "batch_scrape.started",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "metadata": {}
}

batch_scrape.page

Sent for each URL scraped in the batch. The data array contains the page content and metadata.

json
{
  "success": true,
  "type": "batch_scrape.page",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [
    {
      "markdown": "# Page content...",
      "metadata": {
        "title": "Page Title",
        "description": "Page description",
        "url": "https://example.com",
        "statusCode": 200,
        "contentType": "text/html",
        "scrapeId": "550e8400-e29b-41d4-a716-446655440001",
        "sourceURL": "https://example.com",
        "proxyUsed": "basic",
        "cacheState": "miss",
        "cachedAt": "2025-09-03T23:30:53.434Z",
        "creditsUsed": 1
      }
    }
  ],
  "metadata": {}
}

Data Fields

The data array for batch_scrape.page uses the same structure as crawl.page. See the crawl.page field reference above.

batch_scrape.completed

Sent when all URLs in the batch have been processed.

json
{
  "success": true,
  "type": "batch_scrape.completed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "metadata": {}
}

Extract Events

extract.started

Sent when the extract job begins processing.

json
{
  "success": true,
  "type": "extract.started",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "metadata": {}
}

extract.completed

Sent when extraction finishes successfully. The data array contains the extracted structured data, usage info, and source attribution.

json
{
  "success": true,
  "type": "extract.completed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [
    {
      "success": true,
      "data": {
        "siteName": "Example Site",
        "category": "Technology"
      },
      "extractId": "550e8400-e29b-41d4-a716-446655440000",
      "llmUsage": 0.0020118,
      "totalUrlsScraped": 1,
      "sources": {
        "siteName": ["https://example.com"],
        "category": ["https://example.com"]
      }
    }
  ],
  "metadata": {}
}

Data fields for extract.completed:

FieldTypeDescription
data.successbooleanWhether the extraction itself succeeded.
data.dataobjectThe extracted structured data matching your schema.
data.extractIdstringUnique ID for this extraction.
data.llmUsagenumberLLM token cost for this extraction.
data.totalUrlsScrapednumberNumber of URLs that were scraped to produce the extraction.
data.sourcesobjectMaps each extracted field name to the source URL(s) it came from.

extract.failed

Sent when extraction fails. The error field contains the failure reason.

json
{
  "success": false,
  "type": "extract.failed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "error": "Failed to extract data: timeout exceeded",
  "metadata": {}
}

Agent Events

agent.started

Sent when the agent job begins processing.

json
{
  "success": true,
  "type": "agent.started",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [],
  "metadata": {}
}

agent.action

Sent after each tool execution (scrape, search, etc.) the agent performs.

json
{
  "success": true,
  "type": "agent.action",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [
    {
      "creditsUsed": 5,
      "action": "mcp__tools__scrape",
      "input": {
        "url": "https://example.com"
      }
    }
  ],
  "metadata": {}
}

Credits in Action Events

The creditsUsed value in agent.action events is an estimate of the total credits used so far. The final accurate credit count is only available in the completed, failed, or cancelled events.

Data fields for agent.action:

FieldTypeDescription
creditsUsednumberEstimated total credits consumed so far (cumulative).
actionstringThe tool/action that was executed (e.g., mcp__tools__scrape).
inputobjectThe input parameters passed to the tool.

agent.completed

Sent when the agent finishes successfully. Contains the final extracted data and accurate total credits used.

json
{
  "success": true,
  "type": "agent.completed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [
    {
      "creditsUsed": 15,
      "data": {
        "company": "Example Corp",
        "industry": "Technology",
        "founded": 2020
      }
    }
  ],
  "metadata": {}
}

agent.failed

Sent when the agent encounters an error. The error field contains the failure reason.

json
{
  "success": false,
  "type": "agent.failed",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [
    {
      "creditsUsed": 8
    }
  ],
  "error": "Max credits exceeded",
  "metadata": {}
}

Credits on Failure

Even when an agent fails, credits consumed up to the point of failure are still charged. The creditsUsed field in the data array reflects the final credit count.

agent.cancelled

Sent when the agent job is cancelled by the user.

json
{
  "success": false,
  "type": "agent.cancelled",
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "data": [
    {
      "creditsUsed": 3
    }
  ],
  "metadata": {}
}

Event Filtering

By default, you receive all events for the operation type. To subscribe to specific events only, use the events array in your webhook configuration:

json
{
  "url": "https://your-app.com/webhook",
  "events": ["completed", "failed"]
}

This is useful when you only care about job completion and do not need per-page updates. For example, a crawl job that processes 500 pages would send 500+ crawl.page events. If you only need to know when it finishes, filter to ["completed"].

Event Name Quick Reference

Event NameOperationsWhen It Fires
startedCrawl, Batch Scrape, Extract, AgentJob begins processing
pageCrawl, Batch ScrapeEach page/URL is scraped
completedCrawl, Batch Scrape, Extract, AgentJob finishes successfully
failedExtract, AgentJob encounters an error
actionAgentAfter each tool execution
cancelledAgentJob cancelled by user