Run research from code.
Grep API v2 gives you one clean loop: create a research job, watch the execution timeline, then fetch the report, structured output, revisions, and workspace files.
GREP_API_KEY="parcha-..."
curl -X POST "https://api.grep.ai/api/v2/research" \
-H "Authorization: Bearer $GREP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"question": "Due diligence on Stripe Inc",
"effort": "medium"
}'The v2 loop
From API key to report in four calls.
Create a key
Generate a bearer token at /developers/keys and store it server-side as GREP_API_KEY.
POST /research
Submit a question with effort low, medium, high, or build. Add Idempotency-Key only when you need retry-safe creates.
Poll or subscribe
Read /research/{job_id_or_slug} for status, or poll /timeline to show what the agent is doing live.
Use the output
Read report.markdown, structured_output, revisions, and workspace files from the completed job.
What v2 exposes
A small surface for powerful integrations.
Safe retries
Optional Idempotency-Key makes network retries return the original job instead of starting another billable run.
Execution timeline
Cursor-paginated events show tool calls, sub-agent work, final answers, and sanitized previews.
Structured output
Pass json_schema with the job and read the filled fields from structured_output on the detail response.
Input and output files
Upload input files before the job starts, then list or download the files the agent produced.
Credits and usage
Check quota before a run, read credit headers, and query billing usage or transactions for dashboards.
Webhooks
Register webhook_url on create to receive signed callbacks when a job reaches a terminal state.
Create, poll, read report.
The same contract powers the playground and your terminal: API-key auth, idempotent create, defensive polling, and report.markdown as the final prose output.
import os
import time
import requests
API_KEY = os.environ["GREP_API_KEY"]
BASE = "https://api.grep.ai/api/v2"
TERMINAL = {"completed", "complete", "failed", "blocked", "cancelled"}
create = requests.post(
f"{BASE}/research",
headers={"Authorization": f"Bearer {API_KEY}"},
json={"question": "Due diligence on Stripe Inc", "effort": "medium"},
)
create.raise_for_status()
job_id = create.json()["job_id"]
while True:
detail = requests.get(
f"{BASE}/research/{job_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
).json()
if detail["status"] in TERMINAL:
break
time.sleep(2)
print(detail.get("report", {}).get("markdown", ""))Detail response shape.
Completed jobs return the report body, optional structured output, and published report revisions.
{
"job_id": "550e8400-e29b-41d4-a716-446655440000",
"slug": "due-diligence-on-stripe-inc",
"status": "completed",
"report": {
"markdown": "# Stripe Inc\n\nStripe builds financial infrastructure...",
"revision_sha": "9f4c2a1"
},
"structured_output": {
"company": "Stripe Inc",
"risk_flags": []
},
"revisions": [
{ "commit_sha": "9f4c2a1", "checkpoint_type": "new_subjob" }
]
}Docs that map to real routes
Open the exact surface you need.
Build against v2.
The old v1 surface still exists for legacy integrations. New work should start with /api/v2/research and the live v2 reference.