Batch & Bulk Operations
Submit many research jobs in one call with POST /research/batch, or fan out parallel async tasks; plus the multi-result compare primitive
Krawl supports batch/bulk research three ways:
POST /research/batch— submit up to 20 queries in a single request. Each is queued as an independent background task and you get one task handle per query back. This is the formal batch endpoint, defined in/openapi.json.- Parallel async tasks — fan out many
POST /research/asyncjobs and pollGET /tasksmanually (the lower-level equivalent of the batch endpoint). POST /research/compare— a multi-result primitive that diffs two prior results in a single call (useful for change detection over a batch of saved results).
Batch endpoint — POST /research/batch
Submit an array of queries and receive a task handle for each. The server queues them concurrently (subject to a per-key concurrency cap) and never holds open SSE connections.
curl -X POST https://api.krawl.sh/research/batch \
-H "X-API-Key: krawl_live_..." -H "Content-Type: application/json" \
-d '{
"queries": [
{"query": "State of AI agents 2025", "mode": "deep"},
{"query": "DeFi TVL trends Q1", "mode": "quick"},
{"query": "Latest Llama benchmarks", "mode": "deep", "webhook_url": "https://example.com/hook"}
]
}'Response (202 Accepted):
{
"accepted": 3,
"tasks": [
{"id": "550e8400-...", "query": "State of AI agents 2025", "mode": "deep", "status": "queued"},
{"id": "661f9511-...", "query": "DeFi TVL trends Q1", "mode": "quick", "status": "queued"},
{"id": "772fa622-...", "query": "Latest Llama benchmarks", "mode": "deep", "status": "queued"}
]
}| Field | Type | Notes |
|---|---|---|
queries | array (1–20) | Each item: query (required), mode (deep/quick/crypto), optional webhook_url. |
accepted | int | Number of jobs queued. |
tasks[] | array | One task handle per query — poll GET /tasks/{id}. |
Then poll each task (see Pattern A) or use
per-item webhook_url callbacks. If the batch would exceed your active-task cap,
the whole request is rejected with 429 + Retry-After rather than partially
queued — retry with backoff.
Pattern A — parallel async research
Submit each query as its own background task, then poll for completion. The server runs them concurrently (subject to a per-key concurrency cap) and you never hold open SSE connections.
1. Submit jobs
curl -X POST https://api.krawl.sh/research/async \
-H "X-API-Key: krawl_live_..." -H "Content-Type: application/json" \
-d '{"query": "State of AI agents 2025", "mode": "deep"}'{
"id": "550e8400-...",
"query": "State of AI agents 2025",
"mode": "deep",
"status": "queued",
"result_id": null,
"created_at": "2025-01-15T10:00:00Z"
}Repeat for each query in your batch, collecting the returned task ids.
Concurrency cap. Each API key can only have a bounded number of
queued+running tasks at once. When you exceed it, submission returns 429 with
a message like Too many active async tasks (N/MAX). Throttle submissions and
retry with backoff,
or wait for in-flight tasks to finish.
2. Poll for completion
Poll the collection (newest first) or individual tasks:
# All your tasks
curl -H "X-API-Key: krawl_live_..." "https://api.krawl.sh/tasks?limit=50&offset=0"
# A single task
curl -H "X-API-Key: krawl_live_..." "https://api.krawl.sh/tasks/550e8400-..."Each task has a status of queued, running, done, or error. When done,
fetch the report via GET /results/{result_id}:
{
"id": "550e8400-...",
"query": "State of AI agents 2025",
"mode": "deep",
"status": "done",
"result_id": "9f1c2b34-...",
"finished_at": "2025-01-15T10:06:12Z"
}3. (Optional) get notified instead of polling
Pass webhook_url on submission to receive a completed/error callback per
task instead of polling. See Webhooks.
Batch driver (pseudocode)
import time, httpx
queries = ["q1", "q2", "q3", "..."]
client = httpx.Client(base_url="https://api.krawl.sh", headers={"X-API-Key": "krawl_live_..."})
# Submit (respecting the concurrency cap: retry 429s with backoff)
task_ids = []
for q in queries:
r = client.post("/research/async", json={"query": q, "mode": "deep"})
r.raise_for_status()
task_ids.append(r.json()["id"])
# Poll until all terminal
pending = set(task_ids)
while pending:
for tid in list(pending):
t = client.get(f"/tasks/{tid}").json()
if t["status"] in ("done", "error"):
pending.discard(tid)
if t["status"] == "done":
report = client.get(f"/results/{t['result_id']}").json()
# ... use report
time.sleep(5) # poll interval; honor rate-limit headersUse a polling interval (e.g. 5s) and watch
X-RateLimit-Remainingso polling a large batch doesn't trip the rate limiter. See Rate Limits & Retries.
Pattern B — POST /research/compare
compare is the multi-result batch primitive for change detection: it takes
results you already have and returns a structured diff in one call.
Request (CompareRequest):
| Field | Type | Description |
|---|---|---|
query | string | required — query to find/compare results for (1–2000 chars) |
result_ids | string[] | optional, up to 10 — specific results to compare |
Behavior depends on how many result_ids you pass:
- 2+ ids → compares the first two of those results directly.
- 1 id → compares it against the most similar previous result for its query.
- 0 ids → finds the two most recent results matching
queryand compares them.
curl -X POST https://api.krawl.sh/research/compare \
-H "X-API-Key: krawl_live_..." -H "Content-Type: application/json" \
-d '{"query": "AI agents", "result_ids": ["9f1c...", "7b3e..."]}'Response:
{
"old_result_id": "7b3e...",
"new_result_id": "9f1c...",
"old_query": "AI agents",
"new_query": "AI agents",
"old_created_at": "2025-01-08T10:00:00Z",
"new_created_at": "2025-01-15T10:00:00Z",
"changes": [{ "field": "...", "old": "...", "new": "..." }],
"new_findings": ["..."],
"removed_claims": ["..."],
"summary": "Natural-language summary of what changed.",
"has_changes": true
}If fewer than two comparable results exist, compare returns 404 with a
message telling you how many it found — submit more research first.
Choosing a pattern
| Goal | Use |
|---|---|
| Run many independent queries at once | Pattern A (parallel /research/async + /tasks) |
| Detect what changed between two reports | Pattern B (/research/compare) |
| Recurring watch + auto-diff on a schedule | Lookouts |
Trust
How Krawl handles citation, verification, failure modes, refunds, and audit — the methodology page an autonomous agent's owner should read before wiring Krawl into a production pipeline.
Webhooks
Outbound webhook events for async research and scheduled lookouts, the signed payload contract, signature verification, and replay protection