Documentation

vaaya / docs / reference

OneFind

OneFind turns a description of people, or a list of identifiers, into rows: name, title, company, location, LinkedIn, email, phone. Two endpoints share one row format. vaaya/onefind finds people for a flat 2 cents. vaaya/onefind-deep finds and enriches, or enriches a batch you already have, and charges only for fields that fill.

Endpoints

EndpointWhat it doesPriceMode
POST /api/run/vaaya/onefindFind people from a query. No contact data.2 cents per callsync
POST /api/run/vaaya/onefind-deepFind and enrich, or enrich a list of identifiers.per filled field, capped by a budgetasync

Both take a JSON body and a bearer API key. Both return the same row format, described below.

OneFind returns people only. To find companies, use the company vendors on the GTM page.

Find people

Send a plain-English description. Get back up to 25 rows without contact data.

curl -X POST https://vaaya.ai/api/run/vaaya/onefind \
  -H "Authorization: Bearer $VAAYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "heads of growth at B2B SaaS companies in Berlin", "limit": 15}'

Request

FieldTypeRequiredDescription
querystringyesWho you want. A description (role, industry, place, company type) or one person by name and company.
limitintegerno1 to 25. Default 15.

Response

{
  "ok": true,
  "data": {
    "query": "heads of growth at B2B SaaS companies in Berlin",
    "person": false,
    "row_count": 15,
    "enriched": false,
    "rows": [
      {
        "id": "https://www.linkedin.com/in/example",
        "name": "Jane Doe",
        "title": "Head of Growth",
        "company": "Example GmbH",
        "location": "Berlin, Germany",
        "linkedin": "https://www.linkedin.com/in/example",
        "email": null,
        "phone": null,
        "domain": null,
        "industry": null,
        "headcount": null,
        "hq": null,
        "sources": { "name": "exa", "title": "exa", "company": "exa", "location": "exa", "linkedin": "exa" },
        "enriched": false,
        "hops": [],
        "charged_cents": 0
      }
    ],
    "calls": [{ "service": "exa", "action": "search", "ok": true, "latency_ms": 812 }],
    "next": "To add emails and phones, call onefind-deep ..."
  },
  "charged_cents": 2
}

If query names one person, for example "Jerry Liu LlamaIndex", the response has person: true and one row. If it describes a group, person is false and rows is a list to choose from.

An email address or LinkedIn URL as query returns a 400 and is not charged. Those identify one person and belong to onefind-deep.

Find and enrich

Send a query to find people and enrich every row, or send rows to enrich identifiers you already have. The call returns a job_id. Poll it until the job finishes.

curl -X POST https://vaaya.ai/api/run/vaaya/onefind-deep \
  -H "Authorization: Bearer $VAAYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "VP Engineering at fintech companies in London", "limit": 10, "budgetCents": 160}'
curl -X POST https://vaaya.ai/api/run/vaaya/onefind-deep \
  -H "Authorization: Bearer $VAAYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"rows": ["satya@microsoft.com", "linkedin.com/in/satyanadella", "Jerry Liu LlamaIndex"]}'

Request

FieldTypeRequiredDescription
querystringone of query / rowsFind people, then enrich each row. A query that names one person enriches only that person.
rowsstring[]one of query / rows1 to 50 identifiers. Each is an email, a LinkedIn URL, or a name with a company.
limitintegernoRows to find when using query. 1 to 25. Default 15.
budgetCentsintegernoMost you will pay, 10 to 500. Default is 16 cents per row. The job holds this amount until it finishes.

Response

{
  "ok": true,
  "data": {
    "job_id": "7c1d0f6e-...",
    "status": "queued",
    "async": true
  },
  "charged_cents": 0
}

Poll the job

Call result with the job_id until status is succeeded or failed. Jobs usually finish within a minute or two.

curl -X POST https://vaaya.ai/api/run/vaaya/result \
  -H "Authorization: Bearer $VAAYA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_id": "7c1d0f6e-..."}'
{
  "ok": true,
  "job_id": "7c1d0f6e-...",
  "status": "succeeded",
  "result": {
    "query": "VP Engineering at fintech companies in London",
    "row_count": 10,
    "enriched_count": 10,
    "skipped_count": 0,
    "stats": { "emails": 7, "phones": 2 },
    "rows": [ ... ],
    "spent_cents": 84,
    "budget_cents": 160,
    "find": { "service": "exa", "action": "search", "ok": true, "latency_ms": 790 }
  },
  "charged_cents": 84
}

Row format

Every row has the same fields in both endpoints.

FieldTypeDescription
idstringThe LinkedIn URL when known, otherwise the input.
inputstringThe identifier this row came from. Present in rows mode.
name, title, company, location, linkedinstring or nullFilled by the find. Enrichment can overwrite them.
email, phonestring or nullFilled by enrichment only.
domain, industry, headcount, hqstring or nullAbout the company. Filled by enrichment.
sourcesobjectWhich vendor supplied each filled field: exa, contactout, tomba, or input.
enrichedbooleanWhether enrichment ran on this row.
hopsarrayVendor calls made for this row. Each has provider, action, ok, charged_cents, latency_ms, and skipped when the call was not made.
charged_centsintegerWhat this row cost.
errorstringSet when the row could not be resolved. "over budget" means the budget ran out before this row started.

Reading a null

  • email: null with enriched: false. Not looked up. Call onefind-deep to fill it.
  • email: null with enriched: true. Looked up. No vendor had it.

Pricing

  • onefind: 2 cents per call, any limit.
  • onefind-deep: you pay the price of each vendor call that returned data. ContactOut is 10 cents, Tomba is 4 to 5 cents, the Exa lookup is 1 cent. Calls that return nothing are free.
  • The job holds budgetCents (or 16 cents per row) when it starts and releases what it did not spend when it finishes.
  • Rows the budget could not cover are returned with error: "over budget". Raise budgetCents or lower limit.
  • A job that finds nobody is failed and charged 0.

How rows are enriched

Each row goes through a fixed order of vendors. The order comes from measured hit rates, not list prices.

InputFirstThen
emailcontactout/person-from-email (10 cents, free on a miss)tomba/enrich (4 cents). Skipped for webmail addresses.
LinkedIn URLcontactout/linkedin-contacts (10 cents)tomba/linkedin-finder (5 cents)
name and companyexa/search (1 cent) to find the profilethen the LinkedIn URL order above

Errors

StatusErrorMeaning
400bad_requestInvalid body. onefind-deep needs exactly one of query or rows.
400onefind_identifieronefind got an email, LinkedIn URL, or phone number as query. Use onefind-deep.
402credits_requiredBalance is below the budget the job would hold. Add credit, lower limit, or set a smaller budgetCents.
429too_many_inflightThree onefind-deep jobs are already running on this account.
502no_peopleThe search found nobody. Not charged.
  • SuperSearch answers questions. OneFind returns people.
  • GTM & leads lists the individual vendors, including filters OneFind does not expose and company search.