Skip to main content

Use case

Enrich thousands of records at once without managing per-row API calls. Upload a CSV or JSON file, define what you want back with a struct, and download the enriched results when the job completes. Use it for list building, CRM backfills, and large-scale data refreshes.

Endpoint

Use the people endpoint for lead/person rows:
POST https://api.sixtyfour.ai/bulk-intelligence/people
Use the company endpoint for company rows:
POST https://api.sixtyfour.ai/bulk-intelligence/company

People API Reference

Full request/response schema for POST /bulk-intelligence/people.

Company API Reference

Full request/response schema for POST /bulk-intelligence/company.

Pricing

See Credits & Pricing Guide for credit costs by tier.
Before the job starts, Sixtyfour checks that your balance covers the estimated cost. If it doesn’t, the request returns 402 and nothing is charged. The submit response includes estimated_cost_cents. The completed /job-status response includes charge_amount in cents.

Errors

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

Tiers

Allowed tiers depend on the endpoint:
EndpointTiers
/bulk-intelligence/peoplemicro, low (default), medium, high
/bulk-intelligence/companymicro, low (default), medium, high

Request format

Both endpoints take multipart/form-data with two parts:
PartDescription
fileThe records to enrich. Accepts .csv, .json, .jsonl, or .ndjson.
configA JSON-encoded string describing the enrichment — what to return for each row.

Limits

LimitValue
File size100 MB
Rows per file100,000
Config size300,000 characters
Submissions10 per minute per org

The config object

{
  "struct": {
    "email": "The individual's email address",
    "linkedin": "LinkedIn URL for the person"
  },
  "tier": "low",
  "field_confidence": true,
  "webhook_url": "https://your-server.com/webhooks/sixtyfour"
}
For struct value formats, supported types, and casting, see Struct & Type Casting.
high is gated — access is granted case-by-case by our team. Requests for a tier your org doesn’t have access to return 403 — see Handling Errors.

Submitting a job

curl -X POST "https://api.sixtyfour.ai/bulk-intelligence/people" \
  -H "x-api-key: YOUR_API_KEY" \
  -F "file=@leads.csv" \
  -F 'config={
    "struct": {
      "email": "The individual'\''s email address",
      "linkedin": "LinkedIn URL for the person",
      "title": "The individual'\''s job title"
    }
  }'
The response includes the job handle and the cost estimate:
{
  "task_id": "9b1f9d2e-...",
  "status": "RUNNING",
  "row_count": 2500,
  "estimated_cost_cents": 25000
}

Polling for results

Poll GET /job-status/{task_id} until status is completed, failed, or cancelled. When the job completes, the response includes a results array of signed download links for the output files plus charge_amount in cents — bulk jobs deliver files, not an inline result. The results array contains one entry per pipeline stage; the final enriched output is the entry with the highest block_number. Small files also carry an inline results row preview alongside the link — use one or the other, not both.
Download links are signed URLs that expire after 15 minutes — poll again for fresh links — and require your x-api-key header when fetching.
# Check status
curl "https://api.sixtyfour.ai/job-status/TASK_ID" \
  -H "x-api-key: YOUR_API_KEY"

# When status is "completed", download the result (no redirects — pass your key directly)
curl -o enriched.csv \
  -H "x-api-key: YOUR_API_KEY" \
  "SIGNED_DOWNLOAD_URL"
For per-block progress while the job runs, use Workflow Run Live Status.

Webhook callback

Pass a webhook_url in the config to receive results via HTTP POST when the job completes, instead of polling. The payload includes signed download URLs for the result files. The signed payload, retry behavior, and verification steps are documented in Outgoing Webhooks.
Webhook URLs must use HTTPS and resolve to a public address. The URL is validated when you submit and again at delivery time.

Idempotency

Send an Idempotency-Key header (up to 255 characters) to make submissions retry-safe. Resubmitting with the same key returns the original job instead of starting a new one:
{
  "task_id": "9b1f9d2e-...",
  "status": "RUNNING",
  "already_started": true
}
Idempotent replays don’t count against the submission rate limit, and row_count and estimated_cost_cents are omitted, since the original upload is authoritative.

Failure behavior

Rows that fail enrichment pass through to the output un-enriched — a single hard row doesn’t fail the job. If the uploaded file itself can’t be read or parsed, the request fails with 400 before anything runs.