// people and companies

People and company enrichment

The agnt source is superagnt's own. Instead of proxying one vendor, it runs a waterfall across several upstream providers, cheapest first, and returns one normalized record, so you write against a single response shape and stop paying for more providers once your fields are filled.

12 endpointsflat and range pricingbulk up to 100
01// the waterfall

What the agnt source is

Each endpoint has a list of upstream providers, run cheapest first. A call walks the list and stops as soon as your fields are filled, skipping any provider that would push spend past your ceiling, then merges what it found and returns one record in our own schema. It also skips, at no cost, any provider that never returns a field you still lack. The one exception is a max_cost_cents below the full range: there such a provider can still run, because whether a later provider fits your cap can turn on its answer. A provider whose match for the same identifiers, asked by your workspace earlier in the day (UTC), had none of the fields you still lack, and so cost you nothing, is skipped too: asking again would get the same answer. You never branch on which provider answered.

Name the fields you need in fields. Leave it out and the enrich endpoints fill a core set: email, full name, job title, company name and domain, LinkedIn URL and location for a person; name, domain, description, industry, headcount range, HQ location and LinkedIn URL for a company. Every other field is looked up only when you name it. A verified email counts only when the email is valid, a personal email isn't available here, and a mobile number comes from people/find-mobile.

Provider identities are stripped on the way out. Responses never name a vendor, and usage rows record each attempt only by its HTTP status and, when a provider refused the request, a vendor-neutral reason, so a change in the waterfall is invisible to your integration.

02// the endpoints

The endpoints

Twelve POST endpoints under two namespaces. People: email-finder, email-verifier, enrich, find-mobile, search, bulk-enrich. Companies: discover, domain-emails, enrich, search, intelligence, bulk-enrich.

companies/intelligence is one route with a signal of funding, competitors or technographics, plus a domain. Each signal is priced separately.

03// two pricing models

Two pricing models

Flat endpoints run a single provider and charge the same price on every call. The one exception is companies/domain-emails, billed per ten emails returned (an empty result is free), so a smaller limit caps the charge.

POST /v1/data/agnt/people/search
POST /v1/data/agnt/companies/discover
POST /v1/data/agnt/companies/domain-emails
POST /v1/data/agnt/companies/intelligence (funding)
POST /v1/data/agnt/companies/intelligence (competitors)
POST /v1/data/agnt/companies/intelligence (technographics)

Each flat price is published per endpoint rather than fixed in prose. Read it from GET /v1/platforms or on the endpoint page in the API reference, and never copy a number into your own docs or UI.

Range endpoints charge what the waterfall actually spent upstream, at cost, capped by your budget. A lookup the first provider answers costs a fraction of one that walks the whole list. The published range runs from the cheapest single provider to every provider in sequence, and it arrives with each response in meta.priceRange.

Range endpointWaterfall
POST /v1/data/agnt/people/email-findertwo providers in the waterfall
POST /v1/data/agnt/people/email-verifierthree providers
POST /v1/data/agnt/people/enrichthree providers
POST /v1/data/agnt/people/find-mobiletwo providers
POST /v1/data/agnt/people/bulk-enrichthree providers, budgeted per record
POST /v1/data/agnt/companies/enrichthree providers
POST /v1/data/agnt/companies/searchone provider today, so no cost cap is accepted
POST /v1/data/agnt/companies/bulk-enrichthree providers, budgeted per record
04// capping cost

Capping what a call can cost

Range endpoints take max_cost_cents (single call) or max_cost_cents_per_record (bulk). The waterfall skips any provider that would push spend past the ceiling and moves on to the next one, so a cap is a hard limit rather than a hint.

Two ways to get a 400 here. A cap below the endpoint's minimum is rejected, because no provider could run under it and the call would be guaranteed to fail. And a cap on an endpoint that currently has only one configured provider is rejected too, since there is nothing to choose between.

checked vs billed

Your balance is checked against the ceiling before the call runs, so a big cap needs the credits to back it. What you are actually billed is the real upstream spend, which is usually far less. The check is a gate, not a charge.
05// bulk calls

Bulk calls

The two bulk endpoints take 1 to 100 inputs. Each input may carry an identifier, a label of your own that is echoed back on the matching result, which is how you align rows without relying on array order.

bulk enrichbash
curl -X POST "https://api.superagnt.com/v1/data/agnt/people/bulk-enrich" \
  -H "Authorization: Bearer $AGNTDATA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": [
      { "identifier": "row-1", "email": "ada@example.com" },
      { "identifier": "row-2", "linkedin_url": "https://www.linkedin.com/in/example" }
    ],
    "fields": ["email", "job_title", "location"],
    "max_cost_cents_per_record": 4
  }'

Every result reports what happened to that record on its own: fields_returned, fields_missing, providers_attempted and providers_skipped. A record the waterfall could not resolve comes back with a null record rather than failing the batch.

bulk response (figures illustrative)json
{
  "success": true,
  "data": {
    "results": [
      {
        "identifier": "row-1",
        "person": { "...": "normalized record, or null" },
        "fields_returned": ["email", "job_title"],
        "fields_missing": ["location"],
        "providers_attempted": 2,
        "providers_skipped": 0
      }
    ]
  },
  "meta": {
    "costCents": 3.96,
    "purchasedBalanceCents": 4820,
    "subscriptionRemainingCents": 1500,
    "priceRange": { "minCents": 1.98, "maxCents": 6.9535 },
    "budgetCentsPerRecord": 4,
    "records": 2,
    "latencyMs": 2140
  }
}
06// input rules

Input rules that trip people up

People must resolve to an email or a LinkedIn URL. people/enrich, find-mobile and bulk-enrich need at least one of email or linkedin_url. A name plus a company is not accepted. If that is all you have, call people/email-finder first, which is the endpoint that does take a name plus a company and hands you back an email.

Companies need one strong handle. At least one of domain, name / company_name, or linkedin_url. Domain resolves best when you have it.

nesting differs between the two

companies/enrich nests its handles under identifiers. companies/bulk-enrich puts them top-level on each input object instead. Copying the shape from one to the other is the most common 400 on this surface.
07// reading meta

Reading the meta block

Alongside the standard costCents and the two balances, range endpoints add priceRange (the published floor and ceiling), budgetCents (the cap actually applied, yours or the default), providersAttempted, providersSkipped (providers not called: none returns a field you still lacked, or one already matched the same identifiers earlier that day without any of them), fieldsReturned and fieldsMissing. Together they tell you whether a disappointing result was a data gap or a budget you set too low.

Flat endpoints report providersAttempted but no range or budget: the one provider either answers or it does not.

08// when it fails

When the waterfall fails

PROVIDER_ERROR with HTTP 503 means the providers failed on their side, or none could run inside your budget. Widening max_cost_cents is worth trying in the second case.

RATE_LIMITED with HTTP 429 and retryAfter: 5 means every attempt was turned away by pacing upstream. Back off for those five seconds and retry; hammering it will not help.

VALIDATION_ERROR with HTTP 400 on a search means a provider refused one of your filter values, and the message names it, for example an industry that is not on the fixed list. Fix the value and retry.

UPSTREAM_CREDITS_EXHAUSTED with HTTP 503 means our own account with a provider ran dry. That is on our side, we are alerted, and a retry later will work.

A search or lookup that matches nothing is not an error: it returns HTTP 200 with meta.empty set and a meta.notice saying so. Searches return an empty results list, the email finder returns email: null, and enrich and find-mobile return the identifiers you sent with every other field null. Retrying will not find it. An enrich answers the same way when no provider had the fields you named, or when none that returns them could be called at all.

All of these are billed at zero. A failed enrichment or an empty search never costs credits.

A call your data credits cannot cover is refused before any provider runs, and it costs nothing. Calls still running hold their budget, so parallel calls cannot all pass against the same credits. On a builder plan or the no-card trial the refusal is an upgrade offer; while some of the trial's data credit is left, it also says what the call would cost and how much remains. Otherwise it is HTTP 402 INSUFFICIENT_CREDITS.

Full parameter and response schemas for every endpoint are in the API reference, and the rest of the curated catalog is on data sources.