Skip to main content

Use case

Turn partial lead records into full contact profiles for sales outreach, CRM enrichment, or lead qualification.
This endpoint is also available at /enrich-lead and /enrich-lead-async. Both paths are fully supported and functionally identical.

Endpoint

POST https://api.sixtyfour.ai/people-intelligence

API Reference

See the full request/response schema and parameters in the API Reference.

Pricing

See Credits & Pricing Guide for credit costs by tier.

Errors

For error responses (400, 403, 422, etc.), see Handling Errors.

Tiers

The tier parameter controls research depth and cost.
TierDescriptionAccess
microLightweight enrichment — returns up to 10 fields. Best for very high-volume lookups where only minimal data is needed.All orgs
low (default)Baseline tier — fast and cheap. Good for high-volume enrichment where you mostly need a name → email/LinkedIn mapping.All orgs
mediumDeeper research with more sources and iterations. Better for hard-to-find contacts.All orgs
highOSINT-grade investigation — deeply recursive crawling across the open web, dark web, directories, proprietary sources. Designed for the hardest prospects, sensitive diligence, and investigative workflows.Exclusive — access is granted case-by-case by our team. Contact sales to request.
If tier is omitted, low is used. Requests with tier: "high" on an org without high-tier access return 403 — see Handling Errors.

Using the struct field

The struct field defines exactly what data you want back. Each key becomes a field in structured_data, and its value tells the agent what to find. You can pass either a plain-English description or an object with description and type:
{
  "struct": {
    "email": "The individual's email address",
    "github_url": {"description": "URL for their GitHub profile", "type": "str"}
  }
}
The agent uses these descriptions to guide its research. Be specific — "The individual's primary work email" returns better results than "email". For supported types, type resolution priority, and casting examples, see Struct & Type Casting.

Timeouts and parallelization

This endpoint performs deep research and is a long-running operation. Typical P95 runtime is about 5 minutes and can reach 10 minutes for complex leads. We are actively working on performance improvements.
  • Set client timeouts appropriately: If you call the sync endpoint, configure your HTTP client with a timeout of at least 15 minutes.
  • Prefer async in production: Use POST /people-intelligence-async and poll GET /job-status/{task_id}.
  • Parallelize for throughput: Submit multiple async jobs in parallel (bounded concurrency) rather than waiting for each to complete sequentially.

Understanding scores

FieldMeaningRange
confidence_scoreGlobal quality score — overall quality, consistency, and correctness of the returned data.0–10
The findings field on the response is deprecated. It currently returns an empty list and will be removed in a future update.

Sync usage

Make a direct request and wait for the response. Enrichment can take several minutes depending on depth of research.
curl -X POST "https://api.sixtyfour.ai/people-intelligence" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_info": {
      "name": "Saarth Shah",
      "title": "CEO & Co-Founder @ Sixtyfour AI",
      "company": "Sixtyfour AI",
      "location": "San Francisco",
      "linkedin": "https://www.linkedin.com/in/saarthshah"
    },
    "struct": {
      "name": "The individual'\''s full name",
      "email": "The individual'\''s email address",
      "phone": "The individual'\''s phone number",
      "company": "The company the individual is associated with",
      "title": "The individual'\''s job title",
      "linkedin": "LinkedIn URL for the person",
      "website": "Company website URL",
      "location": "The individual'\''s location and/or company location",
      "industry": "Industry the person operates in",
      "github_url": "url for their github profile",
      "github_notes": "Take detailed notes on their github profile."
    }
  }'

Async pattern

For production workflows, use /people-intelligence-async to submit a job and poll for results. This avoids long-lived HTTP connections during deep research runs. The flow is:
  1. SubmitPOST /people-intelligence-async with the same body as the sync endpoint. Response includes a task_id.
  2. PollGET /job-status/{task_id} until status is completed, failed, or cancelled.
  3. Read result — When completed, the full enrichment is in the result field.
The async start endpoint returns uppercase RUNNING. Subsequent /job-status/{task_id} calls return lowercase statuses. charge_amount is returned in cents, not credits.

Polling example

import requests
import time

response = requests.post(
    "https://api.sixtyfour.ai/people-intelligence-async",
    headers={"x-api-key": "YOUR_API_KEY", "Content-Type": "application/json"},
    json={
        "lead_info": {
            "name": "Saarth Shah",
            "title": "CEO & Co-Founder @ Sixtyfour AI",
            "company": "Sixtyfour AI",
            "location": "San Francisco",
            "linkedin": "https://www.linkedin.com/in/saarthshah"
        },
        "struct": {
            "name": "The individual's full name",
            "email": "The individual's email address",
            "phone": "The individual's phone number",
            "company": "The company the individual is associated with",
            "title": "The individual's job title",
            "linkedin": "LinkedIn URL for the person",
            "website": "Company website URL",
            "location": "The individual's location and/or company location",
            "industry": "Industry the person operates in"
        }
    }
)
response.raise_for_status()
task_id = response.json()["task_id"]

while True:
    status = requests.get(
        f"https://api.sixtyfour.ai/job-status/{task_id}",
        headers={"x-api-key": "YOUR_API_KEY"}
    ).json()

    if status["status"] == "completed":
        results = status["result"]
        break
    if status["status"] in ("failed", "cancelled"):
        raise RuntimeError(f"Job {status['status']}: {status.get('error', 'Unknown error')}")

    time.sleep(10)