Overview
Base URL: https://api.exa.ai/websets/v0 Auth: Pass your API key via the x-api-key header. Get one at https://dashboard.exa.ai/api-keys. Websets is an asynchronous search system. You define a query, criteria for verification, and optional enrichments. The system searches, verifies each result, and returns structured items over time. Results are available via polling or webhooks.
Installation
pip install exa-py # Python
npm install exa-js # JavaScript
Minimal Working Example
from exa_py import Exa
from exa_py.websets.types import CreateWebsetParameters, CreateEnrichmentParameters
import os
exa = Exa(os.getenv("EXA_API_KEY"))
webset = exa.websets.create(
params=CreateWebsetParameters(
search={
"query": "Top AI research labs focusing on large language models",
"count": 5
},
enrichments=[
CreateEnrichmentParameters(
description="LinkedIn profile of VP of Engineering",
format="text",
),
],
)
)
print(f"Webset ID: {webset.id}")
print(f"Dashboard: {webset.dashboard_url}")
# Wait for completion
webset = exa.websets.wait_until_idle(webset.id)
# Get results
items = exa.websets.items.list(webset_id=webset.id)
for item in items.data:
print(item.model_dump_json(indent=2))
import Exa from "exa-js";
const exa = new Exa(process.env.EXA_API_KEY);
const webset = await exa.websets.create({
search: {
query: "Top AI research labs focusing on large language models",
count: 10
},
enrichments: [
{ description: "Estimate founding year", format: "number" }
],
});
console.log(`Webset ID: ${webset.id}`);
const idleWebset = await exa.websets.waitUntilIdle(webset.id, {
timeout: 60000,
pollInterval: 2000
});
const items = await exa.websets.items.list(webset.id, { limit: 10 });
for (const item of items.data) {
console.log(JSON.stringify(item, null, 2));
}
# Create a webset
curl -s -X POST "https://api.exa.ai/websets/v0/websets/" \
-H "accept: application/json" \
-H "content-type: application/json" \
-H "x-api-key: ${EXA_API_KEY}" \
-d '{
"search": {
"query": "Top AI research labs focusing on large language models",
"count": 5
},
"enrichments": [
{"description": "Find founding year", "format": "number"}
]
}'
# Check status
curl "https://api.exa.ai/websets/v0/websets/{WEBSET_ID}" \
-H "accept: application/json" \
-H "x-api-key: ${EXA_API_KEY}"
# List items
curl "https://api.exa.ai/websets/v0/websets/{WEBSET_ID}/items" \
-H "accept: application/json" \
-H "x-api-key: ${EXA_API_KEY}"
# Get webset with items expanded
curl "https://api.exa.ai/websets/v0/websets/{WEBSET_ID}?expand=items" \
-H "accept: application/json" \
-H "x-api-key: ${EXA_API_KEY}"
How Websets Work
Lifecycle
- Create — You POST a search config (query, count, optional criteria/enrichments/entity type). A webset is created with status
running. - Search — The system searches and verifies each result against your criteria. Matching items are added to the webset. Each item triggers a
webset.item.createdevent. - Enrichment — If enrichments are configured, each item is processed.
webset.item.enrichedevents fire as enrichment results arrive. - Idle — When all searches and enrichments complete, the webset status becomes
idleand awebset.idleevent fires.
Key Concepts
- Search: Defines what to look for (query + count). Multiple searches can be added to one webset.
- Criteria: Verification rules. Each result is checked against criteria before becoming an item. Max 5 criteria per search.
- Entity: Optional type hint (e.g.
"company","person","article","research_paper","custom") that shapes how results are found and verified. Auto-detected if not specified. - Enrichments: Additional data extraction applied to each item (e.g. “Find the CEO name”). Max 10 per webset.
- Monitors: Scheduled re-runs that keep websets updated. Supports cron expressions.
- Webhooks: Real-time HTTP callbacks for events.
- Imports: Bring your own URLs and run enrichments on them.
- Exports: Bulk download of webset items as CSV/JSON.
API Endpoints — Full Reference
Websets
POST /websets/ — Create a Webset
Request body:
{
"search": {
"query": "AI companies in Europe that raised Series A funding",
"count": 50,
"criteria": [
{"description": "Company is an AI startup"},
{"description": "Company has raised Series A funding"}
],
"entity": {"type": "company"},
"behaviour": "override"
},
"enrichments": [
{"description": "Find the CEO name", "format": "text"},
{"description": "Estimate founding year", "format": "number"},
{"description": "Industry vertical", "format": "options", "options": [{"label": "Healthcare"}, {"label": "Finance"}, {"label": "Education"}, {"label": "Other"}]}
],
"externalId": "my-unique-id",
"metadata": {"project": "market-research"}
}
Field details:
| Field | Type | Required | Description |
|---|---|---|---|
search.query |
string (min 1 char) | Yes | Natural language query. Any URL in the query will be crawled and used as context. |
search.count |
number (>= 1) | No (default 10) | Target number of items to find. Actual results may be fewer depending on query complexity. |
search.criteria |
array (1–5 items) | No | Verification rules. Auto-detected from query if omitted. Each has a description string. |
search.entity |
object | No | One of: { "type": "company" }, { "type": "person" }, { "type": "article" }, { "type": "research_paper" }, { "type": "custom", "description": "Job Postings" }. Auto-detected if omitted. |
search.behaviour |
string | No (default "override") |
"override": reuses existing items, re-evaluates against new criteria, discards non-matching. |
enrichments |
array (max 10) | No | Each enrichment has description (required), format, options, metadata. |
externalId |
string | No | Your own identifier. Can be used in place of webset ID in all GET/PATCH/DELETE calls. Returns 409 if duplicate. |
metadata |
object | No | Arbitrary key-value pairs for the webset. |
Response: A Webset object (see Object Schemas below).
GET /websets/{id} — Get a Webset
{id}can be the webset ID orexternalId.- Query param
?expand=itemsincludes up to 100 items in the response.
Response: A Webset object. When expanded, includes an items array of WebsetItem objects.
GET /websets/ — List All Websets
Query params:
| Param | Type | Description |
|---|---|---|
cursor |
string | Pagination cursor from previous response’s nextCursor. |
limit |
number | Results per page (max 200). |
Response: { "data": [Webset, ...], "hasMore": boolean, "nextCursor": string | null }
Items
GET /websets/{websetId}/items — List Items
Query params:
| Param | Type | Description |
|---|---|---|
cursor |
string | Pagination cursor. |
limit |
number | Results per page. |
Response: { "data": [WebsetItem, ...], "hasMore": boolean, "nextCursor": string | null }
GET /websets/{websetId}/items/{itemId} — Get a Single Item
Response: A WebsetItem object.
Enrichments
POST /websets/{websetId}/enrichments — Add an Enrichment
{
"description": "Find the company's LinkedIn page URL",
"format": "url",
"metadata": {"source": "linkedin"}
}
GET /websets/{websetId}/enrichments/{enrichmentId} — Get Enrichment Status
Response: A WebsetEnrichment object.