Skip to main content

Overview

Base URL: https://api.exa.ai/monitors Auth: Pass your API key via the x-api-key header. Get one at https://dashboard.exa.ai/api-keys Monitors are scheduled, recurring Exa searches. You define a search query and an interval, and the system runs the search automatically and delivers results to your webhook. Each run automatically deduplicates against previous results so you only see new content.

Installation

Minimal Working Example


Endpoints

POST /monitors — Create a Monitor

Creates a monitor and returns it with a one-time webhookSecret. Request body: Response: A Monitor object with an additional webhookSecret field (string). Store this secret immediately — it is only returned once and is needed for webhook signature verification.

GET /monitors — List Monitors

Query params: Response: { "data": [Monitor, ...], "hasMore": boolean, "nextCursor": string | null }

GET /monitors/{id} — Get a Monitor

Response: A Monitor object.

PATCH /monitors/{id} — Update a Monitor

All fields are optional. For search, you can send a partial object (only the fields you want to change). Set trigger to null to remove the schedule. Request body: Response: The updated Monitor object.

DELETE /monitors/{id} — Delete a Monitor

Response: The deleted Monitor object.

POST /monitors/{id}/trigger — Trigger a Run

Starts a run immediately, regardless of the schedule. Works for active and paused monitors. Response: { "triggered": true }

GET /monitors/{id}/runs — List Runs

Query params: Response: { "data": [Run, ...], "hasMore": boolean, "nextCursor": string | null }

GET /monitors/{id}/runs/{runId} — Get a Run

Response: A Run object.

Search Parameters

Nested under search in the create/update request.

Contents Parameters

Nested under search.contents. All fields are optional.

Text Object Options

Highlights Object Options

Prefer highlights: true for the highest-quality default. Only supply this object when you specifically need to guide selection with a custom query or cap output size.

Summary Object Options

Trigger

Nested under trigger in the create/update request. The schedule is anchored to the monitor’s creation time. For example, a monitor created at 2:30 PM with "period": "1d" will run daily at ~2:30 PM (with up to 30 minutes of jitter to spread load).

Webhook

Nested under webhook in the create/update request.

Webhook Events

Webhook Payload

For monitor.run.created and monitor.run.completed, data contains the run object plus a metadata field echoed from the parent monitor. For monitor.created, monitor.updated, and monitor.deleted, data contains the full monitor object.

Slack Routing Pattern

Slack routing identifiers can be stored in monitor metadata and echoed in webhook deliveries to route updates back into the correct thread.
The run payload includes data.metadata.slack_channel_id and data.metadata.slack_thread_id, which can be used to decide where to route the update. Exa does not post to Slack directly.

Webhook Signature Verification

Webhook signature verification lets you confirm that incoming webhook requests actually came from Exa and haven’t been tampered with. Without verification, any external party that discovers your webhook URL could send fake payloads to your endpoint. Use the webhookSecret returned from the create endpoint to verify signatures on every incoming request. Every webhook delivery includes an Exa-Signature header:
To verify:
  1. Extract t (timestamp) and v1 (signature) from the header
  2. Construct the signed payload: {t}.{request_body}
  3. Compute HMAC-SHA256 of the signed payload using your webhook secret
  4. Compare the computed signature with v1 using constant-time comparison

Object Schemas

Monitor Object

Run Object

Grounding

Each entry in output.grounding provides source citations for a field in the output:

Monitor Statuses

Monitors have three possible statuses. An active monitor runs on its interval schedule and accepts manual triggers. A paused monitor stops running on schedule but still accepts manual triggers via the trigger endpoint — useful for temporarily halting a monitor without deleting it. A disabled monitor does not run at all; this status is set automatically by the system and cannot be set via the API.

Fail Reasons

Output Schema

outputSchema controls how the search synthesizes results into structured output. It supports two modes:

Text mode (default when no schema is provided)

When outputSchema is omitted or set to { "type": "text" }, the run output’s content field contains a plain text summary synthesized from the search results.
The description field guides the synthesis. When outputSchema is omitted entirely, the system generates a text summary based on the search query.

Object mode

When type is "object", you provide a JSON Schema that defines the structure of the output. The search extracts and organizes information from results to match your schema.
When outputSchema is set, completed runs include:
  • output.content shaped to your schema
  • output.grounding with field-level citations and confidence scores

Automatic Deduplication

Monitors deduplicate results across runs using two layers: Date-based filtering. Each run only fetches content published or crawled since the last run. The system uses the interval period to compute a time window with a 2x overlap buffer, so content published between runs is captured even with slight timing variations. Semantic deduplication. The system tracks outputs from the last 5 runs and uses them to focus on new developments. This prevents the same stories or data points from appearing repeatedly.

Error Handling

Error response shape:

Common Mistakes

LLMs frequently generate these incorrect patterns:

Patterns and Gotchas

  • Do not set a type field on search params. Monitors handle this internally. Runs typically take 5-60 seconds.
  • Store webhookSecret immediately. It is only returned in the create response and is needed for webhook signature verification. It cannot be retrieved later.
  • Use trigger for automation, manual trigger for testing. You can create a monitor without a trigger and use POST /monitors/{id}/trigger to run it on demand. This is useful for testing before adding a schedule.
  • Paused monitors still accept manual triggers. Set status to paused to stop the interval schedule while keeping the monitor available for on-demand runs.
  • Monitor run time is anchored at creation time. To create a monitor that runs at a specific time, it should be created when you want the monitor to run.
  • outputSchema controls structured output. See Output Schema for details on type: "text" vs type: "object".
  • Python SDK response attributes use snake_case. Access response fields with snake_case: monitor.webhook_secret, monitor.next_run_at, run.fail_reason. Request dicts use camelCase keys matching the API (e.g., {"numResults": 10}). Alternatively, use typed Pydantic models (CreateSearchMonitorParams, UpdateSearchMonitorParams) with snake_case field names.
  • Webhook events default to all. If you omit events in the webhook config, all event types are delivered.
  • Use metadata for Slack routing. Store Slack identifiers like slack_channel_id and slack_thread_id in monitor metadata; run webhooks echo them back in data.metadata.
  • Overlap prevention. If a run is still in progress when the next scheduled time arrives, the in-progress run is cancelled.

SDK Auto-Pagination Helpers

Both SDKs provide helpers that handle pagination automatically when listing monitors or runs.

Complete Examples

Monitor with structured output and contents

Manual-only monitor (no schedule)

Full lifecycle

Last modified on July 19, 2026