Build with Verona
API for SOTA people and company search.
Getting Started
Get your API key
Sign up at verona.com/signup and create an API key from the API dashboard.
Make a request
Create a thread, start a run with your query, then poll for results. Include your API key in the x-api-key header. See Code Examples for full walkthroughs.
Parse the response
Read values.response for a research summary and iterate over values.enriched_entities for structured results with LinkedIn URLs, company domains, and more.
Overview
The async/polling pattern is ideal for long-running queries where you don't want to hold an HTTP connection open. Instead of blocking until the agent finishes, you create a thread, kick off a background run, poll for completion, then fetch the results.
1. Create a thread — a container for your run's state.
2. Start a run — the agent begins executing in the background.
3. Poll status — check every few seconds until status is "success" or a terminal state.
4. Fetch results — read the thread state once complete.
Tip: Runs can take 20+ minutes for complex queries. Poll every 5–10 seconds and set generous timeouts on your HTTP client. The polling pattern lets you track progress and handle retries gracefully.
Note: The /threads/{id}/state endpoint wraps results in a values object — access your data via values.response and values.enriched_entities.
Endpoints
/threadsCreate a new thread/threads/{thread_id}/runsStart a background run/threads/{thread_id}/runs/{run_id}Poll run status/threads/{thread_id}/stateFetch results (when status = "success")Code Examples
# Step 1: Create a thread
THREAD_ID=$(curl -s -X POST https://verona-research-api-c3bc6a9f802b56f398b17ba2b798fa2f.us.langgraph.app/threads \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{}' | jq -r '.thread_id')
echo "Thread: $THREAD_ID"
# Step 2: Start a background run
RUN_ID=$(curl -s -X POST https://verona-research-api-c3bc6a9f802b56f398b17ba2b798fa2f.us.langgraph.app/threads/$THREAD_ID/runs \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"assistant_id": "c926ac5a-b04e-5949-878a-8e4830d4338b",
"input": {
"input": "AI engineers at YC startups in San Francisco",
"entity_type": "people",
"target_count": 10,
"required_enrichment_fields": ["linkedin_url", "company_domain""]
}
}' | jq -r '.run_id')
echo "Run: $RUN_ID"
# Step 3: Poll until complete
while true; do
STATUS=$(curl -s \
https://verona-research-api-c3bc6a9f802b56f398b17ba2b798fa2f.us.langgraph.app/threads/$THREAD_ID/runs/$RUN_ID \
-H "x-api-key: YOUR_API_KEY" \
| jq -r '.status')
echo "Status: $STATUS"
[ "$STATUS" = "success" ] && break
[ "$STATUS" = "error" ] && echo "Run failed" && exit 1
sleep 5
done
# Step 4: Fetch results
curl -s https://verona-research-api-c3bc6a9f802b56f398b17ba2b798fa2f.us.langgraph.app/threads/$THREAD_ID/state \
-H "x-api-key: YOUR_API_KEY" \
| jq '.values.enriched_entities'Body parameters
application/jsonassistant_idstringrequiredThe agent assistant ID.
Example: "c926ac5a-b04e-5949-878a-8e4830d4338b"
input.inputstringrequiredNatural language description of the target entities you want to find.
Example: "AI engineers at YC startups in San Francisco"
input.entity_typestringrequiredThe type of entity to search for. Must be "people" or "companies".
Example: "people"
input.target_countnumberNumber of results to return.
Example: 10
input.required_enrichment_fieldsstring[]Fields that must be populated. Options: "linkedin_url", "company_domain", "x_url". Default: ["linkedin_url"].
Example: ["linkedin_url", "company_domain"]
input.optional_enrichment_fieldsstring[]Best-effort fields. Same options as required_enrichment_fields. Default: [].
Example: ["x_url"]
Responses
1. Create Thread
POST /threads
{
"thread_id": "d9f5e8a2-3b1c-4f7a-9e6d-2c8b4a1f5e3d",
"created_at": "2025-01-15T10:30:00Z",
"metadata": {}
}2. Start Run
POST /threads/{thread_id}/runs
{
"run_id": "a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6",
"thread_id": "d9f5e8a2-3b1c-4f7a-9e6d-2c8b4a1f5e3d",
"assistant_id": "c926ac5a-b04e-5949-878a-8e4830d4338b",
"status": "pending",
"created_at": "2025-01-15T10:30:01Z"
}3. Poll Status
GET /threads/{thread_id}/runs/{run_id}
{
"run_id": "a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6",
"thread_id": "d9f5e8a2-3b1c-4f7a-9e6d-2c8b4a1f5e3d",
"status": "running",
"created_at": "2025-01-15T10:30:01Z"
}4. Fetch Results
GET /threads/{thread_id}/state
{
"values": {
"response": "Found 10 AI engineers at YC-backed startups in San Francisco...",
"enriched_entities": [
{
"name": "Jane Smith",
"description": "ML Engineer at Acme AI (YC W24)",
"rationale": "AI engineer at a YC-backed startup based in SF",
"current_company": "Acme AI",
"current_title": "ML Engineer",
"linkedin_url": "https://linkedin.com/in/janesmith",
"company_domain": "acmeai.com"
},
...
],
// ... other state fields (plan, past_steps, scratchpad, etc.)
}
}Response fields
These fields are nested inside the values object returned by GET /threads/{thread_id}/state.
responsestringNatural language summary of the research performed
enriched_entitiesobject[]Array of discovered entities with enriched data
enriched_entities[].namestringEntity name
enriched_entities[].descriptionstringBrief description
enriched_entities[].rationalestringWhy this entity matches the query
enriched_entities[].current_companystring?Current company (people only)
enriched_entities[].current_titlestring?Current title (people only)
enriched_entities[].company_namestring?Company name (companies only)
enriched_entities[].domainstring?Company domain (companies only)
enriched_entities[].linkedin_urlstring?LinkedIn URL (if requested)
enriched_entities[].company_domainstring?Company domain (if requested, people only)
enriched_entities[].x_urlstring?X/Twitter URL (if requested)
Status codes
200Success — run completed
401Invalid or missing API key
429Rate limit exceeded (check Retry-After header)
408Agent run exceeded time limit
500Internal server error
Run status values
pendingQueued, not yet executing
runningActively executing
successComplete — fetch results from /threads/{id}/state
errorFailed with internal error
timeoutExceeded max execution time
interruptedManually cancelled