---
name: datacircle
description: Every GTM API plan on datacircle.dev, as one file you download and query. LinkedIn profiles, people and company search, find and validate email and phone, company data, jobs and posts, each plan with its price per 1,000, score, rate limits, the fields it returns and its docs. Use it to compare or price a GTM data API.
---

# Datacircle

Datacircle lists all the GTM APIs. This skill gives you every plan on datacircle.dev as one file.

## When to use

Use it to compare or price a GTM data API.

## 1. Download it

```bash
curl -sL --compressed -o datacircle.json https://datacircle.dev/datacircle.json
```

Or the same rows and columns as CSV: `https://datacircle.dev/datacircle.csv`. In the CSV, we write each list or object as JSON.

## 2. The model

One row is one plan of one call. A provider's plan that covers two calls is two rows. Every row has every key below. Prices are in dollars, except `pay`, which is in the plan's `currency`.

| Key | Type | Meaning |
|---|---|---|
| `name` | text | The row's name, unique on the sheet: the provider, then the plan's price, like "API Builderz, $50 monthly", "HarvestAPI, $280 pack", "Crawlbase, pay as you go", "Bright Data, top-up" (a prepaid balance of any amount), "free" or "contact us". If two plans share a price, we add the plan's name, then the call's method and path, its units and the call's name, until no two rows share a name. We build the name for the sheet and leave it out of the sheet's CSV and JSON. datacircle.json and datacircle.csv have the name from its API's sheet. |
| `provider` | text | Who sells the endpoint. On the sheet, it starts each row's API plan. |
| `api` | text | This column names each row's API. "Employee profile" returns a person's LinkedIn profile, on LinkedIn profiles. "Employee email" finds a person's work email, on Find email. "Email validation" checks whether an address takes mail, on Validate email. "Employee phone" finds a person's phone number, on Find phone. "Company profile" returns a company's LinkedIn page, on LinkedIn company profiles. "Company headcount" counts a company's staff, on its own sheet. "Phone validation" checks whether a phone number is valid, on Validate phone. "Post comments" returns the comments on a LinkedIn post, on LinkedIn post comments. "Post reactions" returns who reacted to a LinkedIn post and how, on LinkedIn post reactions. "Employee lookalikes" returns people similar to the one you send, on Similar people. "Company lookalikes" returns companies similar to the one you send, on Similar companies. "Company technologies" returns the tools a company uses, on its own sheet. "Company job count" counts the jobs a company has open on LinkedIn, on its own sheet. "Employee posts" returns a person's LinkedIn posts, on LinkedIn person posts. "Company posts" returns a company's LinkedIn posts, on LinkedIn company posts. "Company funding" returns a company's funding rounds, on its own sheet. "Company jobs" returns the jobs a company has open, on Company open jobs. "Employee search" finds people by job title, company and place, on LinkedIn people search. "Company search" finds companies by industry, size and place, on LinkedIn company search. "Job search" finds jobs by title, company and place, on LinkedIn job search. "Reverse email lookup" finds the person behind an email, on its own sheet. "Post search" finds posts by keyword, on LinkedIn post search. "Post details" returns a post from its URL or ID, on LinkedIn post details. "Job details" returns a job from its URL or ID, on LinkedIn job details. "Employee comments" returns the comments a person left on posts, on LinkedIn person comments. "Employee reactions" returns the posts a person reacted to, on LinkedIn person reactions. "Post reposts" returns the people who reposted a LinkedIn post, on LinkedIn post reposts. "Employee recommendations" returns the recommendations on a person's LinkedIn profile, on LinkedIn person recommendations. "Job lookalikes" returns jobs similar to the one you send, on Similar jobs. "Employee articles" returns a person's LinkedIn articles, on LinkedIn person articles. "Company enrichment" returns a company's profile from the provider's own database, on Company enrichment. "People search" finds people in the provider's own database. "Company discovery" finds companies in the provider's own database. "Job postings" finds job postings in the provider's own database. "Job posting details" returns a job posting from its ID. "Person enrichment" returns a person's profile from the provider's database. "Leadership changes" returns the new hires, promotions and departures in a company's senior roles. "Company hierarchy" returns a company's parent companies and subsidiaries. Pick an API from the GTM APIs list on the sheet's left, or pick All GTM APIs to see all thirty-eight in one sheet. We name each folder in the zip after its API. |
| `category` | text | Where the row's API sits in the GTM APIs list on the sheet's left: its category, like "Contact", its subcategory, like "Email", and the sheet that holds it, like "Find email" for the Employee email API. Blank (`null` in the JSON) for an API the list doesn't hold yet. Only datacircle.json and datacircle.csv have them. |
| `subcategory` | text | Where the row's API sits in the GTM APIs list on the sheet's left: its category, like "Contact", its subcategory, like "Email", and the sheet that holds it, like "Find email" for the Employee email API. Blank (`null` in the JSON) for an API the list doesn't hold yet. Only datacircle.json and datacircle.csv have them. |
| `sheet` | text | Where the row's API sits in the GTM APIs list on the sheet's left: its category, like "Contact", its subcategory, like "Email", and the sheet that holds it, like "Find email" for the Employee email API. Blank (`null` in the JSON) for an API the list doesn't hold yet. Only datacircle.json and datacircle.csv have them. |
| `page` | text | The address of the plan's own page on datacircle.dev. Only datacircle.json and datacircle.csv have it. |
| `website` | text | The provider's website. |
| `pricingPage` | text | The page where you buy the plan: the provider's pricing page, or the plan's page on another site, like RapidAPI. The button on the plan's page links to it. |
| `pitch` | text | How the provider sells the row's call, quoted from the call's own page, or the provider's own pitch when one page covers all its calls. "[...]" marks a cut. |
| `strengths` | list | The plan's strengths, which we work out from its row: each one is a band that many plans of its API are in. Each API has its own strengths, listed and explained under Strengths on datacircle.dev/fields, and Validate email, Find phone, Validate phone, LinkedIn company profiles, Company headcount, LinkedIn post comments, LinkedIn post reactions, Similar people, Similar companies, Company technologies, Company job count, LinkedIn person posts, LinkedIn company posts, Company funding, Company open jobs, LinkedIn people search, LinkedIn company search, LinkedIn job search, Reverse email lookup, LinkedIn post search, LinkedIn post details, LinkedIn job details, LinkedIn person comments, LinkedIn person reactions, LinkedIn post reposts, LinkedIn person recommendations, Similar jobs, LinkedIn person articles, Company enrichment, People search, Company discovery, Job postings, Job posting details, Person enrichment, Leadership changes and Company hierarchy have none yet. Blank (`[]` in the JSON) when the plan has none, and we leave Strengths off its page. Under Filters, you see only the rows with every strength you tick. |
| `aggregators` | list | Aggregators like treg and Deepline that sell the row's call: with one aggregator account you reach many providers. Each cell says what a call through the aggregator costs with your own provider key, and what 1,000 profiles cost when you pay the aggregator, with no account at the provider: "treg: your key free, paid $1.50". We add "per 1,000 results" when the aggregator charges per profile it finds, and say "paid, no fixed price" when the aggregator publishes no price. On a call the aggregator charges by the page, we price 1,000 results at the largest page size, and we write "paid, page size not stated" when the aggregator doesn't say how many results a page holds. We write "listed, how it's sold not stated" when the aggregator lists the call but doesn't say if you pay the aggregator or use your own key. When the aggregator sells one of the provider's calls and doesn't say which, we add "this call or another", then the provider's name and "call". "none" when no aggregator we checked for the row's API sells the call. A blank cell (`null` in the JSON) means we haven't checked any aggregator for that API. We skip calls an aggregator doesn't list. In the JSON, each aggregator has its `aggregator`, its page there under `url`, `ownKey`, what a call on your own key costs there, or null when you can't use yours, `paid`, true when you can pay the aggregator, or null, as `ownKey` is, when it doesn't say how it sells the call, `callStated`, false when it sells this call or another of the provider's and doesn't say which, `usd`, its price for one `per` in dollars, or null when it sets no price, `perThousand`, its price for 1,000 in dollars, `per`, "call", "result" or "page", and `resultsPerPage`, the most a page holds, or null. |
| `waterfall` | list, or empty | On a call that tries one provider after another until one finds the profile, like treg's: each provider it tries, in order, with its price per 1,000 on this plan, how often it finds the profile, and "misses billed" when it charges for a miss. On a call that returns a page, when a provider charges by the page, we count the full pages that hold 1,000 results at the largest page size, and we write "page size not stated" when the provider doesn't say how many results a page holds. The router publishes how often each provider finds a profile over all its calls, and we assume each provider keeps that rate on the calls the earlier providers miss. Blank on other calls. In the JSON, each step has its `provider`, its `call`, which you can also call alone, its `perThousand`, its `per`, its `resultsPerPage`, as in the row, its `hitRate`, from 0 to 1 or null when the router gives none, and `missesBilled`. |
| `freshness` | text, or empty | How old the answer may be, from the provider's pages. "live": the provider reads LinkedIn, the company's website or its job board, or finds or checks the email or phone number, when you call. "1 month" or "30 days": the provider answers from a copy it refreshes that often. "as of 2025-11-13": from a copy last refreshed that day. "stored": from a copy the provider's pages don't date. Blank (`null` in the JSON) when its pages don't say. In brackets, we list the fields whose freshness differs on the provider's pages. `fieldFreshness` gives each of them its own freshness. Bright Data's LinkedIn profile is "live (current title, jobs, schools: as of 2025-11-13)", since LinkedIn put those three behind its login wall and Bright Data serves them from its cache. |
| `fieldFreshness` | object, or empty | How old the answer may be, from the provider's pages. "live": the provider reads LinkedIn, the company's website or its job board, or finds or checks the email or phone number, when you call. "1 month" or "30 days": the provider answers from a copy it refreshes that often. "as of 2025-11-13": from a copy last refreshed that day. "stored": from a copy the provider's pages don't date. Blank (`null` in the JSON) when its pages don't say. In brackets, we list the fields whose freshness differs on the provider's pages. `fieldFreshness` gives each of them its own freshness. Bright Data's LinkedIn profile is "live (current title, jobs, schools: as of 2025-11-13)", since LinkedIn put those three behind its login wall and Bright Data serves them from its cache. |
| `history` | text, or empty | How far back the answers reach, on an API whose answers are dated, such as a company's funding rounds or its open jobs. "since 2016": back to 2016. "open only": only what is open now. "the last 7 days": a window that ends today. "no limit": every one ever. ", closed only" after it: the closed ones alone. Blank (`null` in the JSON) when the provider's pages don't say, or when the answers aren't dated. |
| `keep` | text | How long the provider's terms let you keep its API's answers. "no limit" when they set none. "no API terms" when the provider has no API terms. |
| `use` | text | What the provider's terms let you use its API's answers for, and what they ask in return, like a link back or a credit. "any" when they limit nothing and ask nothing. "no API terms" when the provider has no API terms. |
| `plan` | text | The plan, as the provider names it on its pricing page. |
| `who` | text | Who the provider offers the plan to: "anyone", or the condition its pages set, like "anyone with a work email" or "on approval of an application". |
| `billing` | text | How you pay: "free", "on-demand" (you pay for what you use, with nothing to buy first), "one-time" (a pack you pay for first, then use), "monthly", "quarterly" (every three months), "half-yearly" (every six months) or "yearly" (a subscription), or "contact" (no public price: you ask the provider for one). On the sheet, "one-time" reads "pay first" and "on-demand" "pay as you go". |
| `charged` | text, or empty | On a pay-as-you-go plan ("on-demand"), when the provider takes the money: "per call" when you pay for each call, from a wallet (AnyAPI, Scrappa and Tomba take USDC by x402 or MPP), "monthly" when the provider bills you each month for what you used (Crawlbase, the RapidAPI plans), "at a threshold" when the provider bills you each time you owe a set amount (API Direct, at $10). Blank (`null` in the JSON) on every other plan. The sheet shows Charged in its Pay column. |
| `pay` | number, or empty | The plan's price, in its `currency`. On a subscription, it covers the months in `termMonths`, and the sheet's CSV writes those months after the price: "$39.00/month", "€99.00/month" on a plan in euros, or "$468.00/15 months" on gtm-api.com's yearly plan. On a pack, it covers the pack. $0.00 on a free plan. Blank (`null` in the JSON) on a top-up when the provider lists no minimum. On a usage tier, your monthly cost before you reach the tier: the lower tiers' calls at their own prices, such as $583 before Crawlbase's next 10M requests, or the tier's minimum if higher. On a pay-as-you-go plan, the sheet's Pay column shows Charged. |
| `currency` | text | `currency` is the currency of the plan's Pay, as an ISO 4217 code: "USD" for dollars, "EUR" for euros. `exchangeRate` is the dollars one unit of it buys: 1 for dollars. |
| `exchangeRate` | number | `currency` is the currency of the plan's Pay, as an ISO 4217 code: "USD" for dollars, "EUR" for euros. `exchangeRate` is the dollars one unit of it buys: 1 for dollars. |
| `termMonths` | number, or empty | On a subscription: how many months its Pay buys. 1, 3, 6 or 12 on a monthly, quarterly, half-yearly or yearly plan, unless the provider gives more months for the same price: gtm-api.com's yearly plans run 15 months for the price of 12. Blank (`null`) on every other plan. |
| `perMonth` | number, or empty | On a subscription: its price for one month in dollars, its Pay divided by the months it buys (`termMonths`), 12 on most yearly plans. We work it out for the sheet, to the cent. We leave it out of the sheet's CSV and JSON, and datacircle.json and datacircle.csv have it. Blank (`null`) on every other plan. |
| `score` | number, or empty | We score each plan out of 100 on price, data, cost to get started, bundle and performance. We score data and performance from our benchmark of the provider's call. Until we benchmark it, they are N/A, and so is the Overall score. We rank a plan's price against its API's other scored plans, and score cost to get started and bundle on the plan alone. We give N/A to free, yearly and contact us plans, plans over $500 to start, plans bought on a marketplace and plans that need your own LinkedIn account. Click Score in the sheet's bar to set the five weights. The JSON, datacircle.json and datacircle.csv give each plan's score at the default weights, empty for N/A. The sheet's CSV has no scores. |
| `priceScore` | number, or empty | The plan's price score out of 100: its cost of 1,000 ranked against the other scored plans of its API, and what a call that finds nothing costs. Point at it to see why. |
| `dataScore` | number, or empty | The plan's data score out of 100, from our benchmark of its provider's call: how complete the call's answer is, or how often it is right, depending on the API. Until we benchmark the call, the score is N/A, and so is the Overall score. Point at the score to see how we scored it. |
| `bundleScore` | number, or empty | The plan's score out of 100 for the other calls its price also gets you, as its pages list them under Also pays for. Point at it to see why. |
| `costToGetStartedScore` | number, or empty | The plan's score out of 100 for what it takes to get your first result: who can get it, how you pay, and the least you pay before it. Point at it to see why. |
| `performanceScore` | number, or empty | The plan's performance score out of 100, from our benchmark of its provider's call: the fastest benchmarked provider's median time divided by this provider's. Until we benchmark the call, the score is N/A, and so is the Overall score. Point at the score to see how we scored it. |
| `units` | number, or empty | What the plan gives for its price, counted in `unit`. On a usage tier, where the tier starts: "from the 51st call a month". |
| `from` | number, or empty | On a usage tier, like Crawlbase's pay as you go: `from` is the monthly profile count where the tier's price starts, a call or a result as `per` counts it. `graduated` is true when the tier's price covers only the profiles from `from` on, with each lower tier at its own price. It is false when every profile of the month costs this tier's price. Both are null on every other plan. |
| `graduated` | true/false, or empty | On a usage tier, like Crawlbase's pay as you go: `from` is the monthly profile count where the tier's price starts, a call or a result as `per` counts it. `graduated` is true when the tier's price covers only the profiles from `from` on, with each lower tier at its own price. It is false when every profile of the month costs this tier's price. Both are null on every other plan. |
| `to` | number, or empty | On a usage tier: the last call or result the tier's price covers each `renews`. It is one less than where the next tier on the same call starts, its `from`. Blank (`null`) on the last tier and on every other plan. Only datacircle.json and datacircle.csv have it. |
| `unit` | text | What the provider's prices count: "credit", "request" for a call, "result" for a profile a call returns, "usd" for a prepaid dollar balance, "execution hour" for an hour its servers run your job, "linked account" for a LinkedIn account you connect, or "seat" for a user. |
| `renews` | text, or empty | When `units` come back: "day", "month", "quarter", "half-year", "year", or "never". On a monthly plan whose units come back each day, you pay for 30 days of them. A yearly, half-yearly or quarterly plan has "month" when its units come a month at a time, and "year", "half-year" or "quarter" when you get them all at once. |
| `expires` | text, or empty | When the units you don't use lapse, in the provider's words: "never", "365 days", "at renewal: unused credits do not carry over". Blank when its pages don't say. |
| `calls` | number, or empty | The number of profiles you get for the plan's price, counted in `per`. A call and a result are each one profile. On a plan that charges by the page, the number of pages. `calls` is the number the plan's units pay for: "100 calls, once" for a free trial, "1,250 results a month" for an allowance. `monthlyCap` is for a call that costs 0 units, like a flat fee: the most profiles you get a month, or "no limit". With a daily or monthly call limit, `monthlyCap` is that limit over 30 days: 90,000 for 3,000 calls a day, which Enough for shows as "90,000 calls a month". Enough for shows `calls`, or `monthlyCap` when a row has no `calls`. It is blank, with `null` in both, when the provider doesn't say how many you get or a waterfall's average call costs nothing. |
| `monthlyCap` | text or number, or empty | The number of profiles you get for the plan's price, counted in `per`. A call and a result are each one profile. On a plan that charges by the page, the number of pages. `calls` is the number the plan's units pay for: "100 calls, once" for a free trial, "1,250 results a month" for an allowance. `monthlyCap` is for a call that costs 0 units, like a flat fee: the most profiles you get a month, or "no limit". With a daily or monthly call limit, `monthlyCap` is that limit over 30 days: 90,000 for 3,000 calls a day, which Enough for shows as "90,000 calls a month". Enough for shows `calls`, or `monthlyCap` when a row has no `calls`. It is blank, with `null` in both, when the provider doesn't say how many you get or a waterfall's average call costs nothing. |
| `perThousand` | number, or empty | Dollars for 1,000 profiles on this plan. 0 on a free plan. On a plan that charges by the page, the price of the full pages 1,000 profiles need, at the most profiles a page holds, and blank when the provider doesn't say how many profiles a page holds. On a flat fee, we spread the fee over the most profiles the plan allows in the months the fee pays for. A flat fee with no cap has no price per 1,000 profiles: the sheet says "no limit", and we leave it blank in the CSV and JSON. Blank too when the call costs no units and the provider doesn't say how many profiles the plan allows. On a waterfall's paid plan, the average cost of a call: the price of each provider under Waterfall, weighted by how often a call reaches it. Blank when the router gives no hit rate or no page size for a provider a call can reach. |
| `listPerThousand` | number, or empty | For a provider that prices in dollars, like an Apify Actor: dollars for 1,000 profiles at its list price. Apify sells a year of credit at a discount: on Starter, $204 buys $228 of credit, twelve months at $19. An Actor's yearly plans then cost less per 1,000 than its list price. On a discounted plan, we name who gives the discount when you hover its $ per 1,000 on the sheet, and under its price on the plan's page. Blank (`null` in the JSON) when the provider prices in its own credits or calls, or when its pages don't say what a profile costs. |
| `overagePerThousand` | number, or empty | On a subscription: dollars for 1,000 profiles past the plan's units, when the provider sells them. |
| `addons` | list, or empty | On an email API's subscription: the packs of units the provider sells on top of the plan, as its pricing page lists them. Each has its `units`, its `pay` in the plan's currency, when it `renews` ("month" or "year" when you pay for it again with the plan, "never" when you buy it once), and its `perThousand`, dollars for 1,000 emails at its price. The sheet's CSV says "500 credits a month for $10 ($20.00 per 1,000)". An empty list when the provider sells none. Blank (null) on every other plan. |
| `notFoundPerThousand` | number, or empty | Dollars for 1,000 profiles, emails, phones, companies, posts or jobs the provider can't find or check, or searches that find nothing. 0 when the provider charges nothing for them, as on free plans. On a waterfall, the cost of a call when no provider finds the answer: the sum of the prices of the providers that charge for a miss. |
| `catchAllPerThousand` | number, or empty | On an email API: dollars for 1,000 calls that return an address at a catch-all domain. Such a domain takes mail for any address, so you can't check whether the person's mailbox exists, and the email may bounce. 0 when they cost nothing, or when the provider returns no such address. The same as the row's $ per 1,000 when the provider charges for any address it finds. Blank when its pages don't say. |
| `bounceRefund` | text, or empty | On an email API: the credit or refund the provider gives when an address it charged you for bounces, and the conditions, in its pages' words, like "the credit, reported from the dashboard or the API and reviewed". "never" when its pages say a bounced address stays charged. Blank when they don't say. |
| `repeatFree` | text, or empty | On a call that costs units: how long after you pay for a profile you can get it again free on this plan. On a flat fee with a daily or monthly limit: how long after you get a profile you can get it again without using up the limit. From the provider's pages: "20 minutes", "no limit" when the provider never charges again for a profile you paid for once, or "never" when they say they charge every repeat. Blank when its pages don't say. |
| `startPerCall` | number, or empty | Dollars you pay once for each call, on top of its price per profile, like an Apify Actor's start fee. You pay it once for a call of 1,000 profile URLs or a call of one. We leave it out of the $ per 1,000. $0.00 on a free plan, and blank when the plan charges none. |
| `per` | text, or empty | The price counts a "call", which asks for one profile, or a "result", each profile a call returns. Some calls return a page of results: a post's comments, reactions or reposts, a person's or company's posts, a person's articles, comments or reactions, a company's open jobs, the people, companies, jobs or posts a search finds, or people, companies or jobs similar to the one you send. "result" counts each one. "page of 50" counts each page, and you pay for a whole page even when it holds fewer than 50. `resultsPerPage` is the most a page holds, or `null`. "page, size not stated" means the provider doesn't say how many a page holds. |
| `resultsPerPage` | number, or empty | The price counts a "call", which asks for one profile, or a "result", each profile a call returns. Some calls return a page of results: a post's comments, reactions or reposts, a person's or company's posts, a person's articles, comments or reactions, a company's open jobs, the people, companies, jobs or posts a search finds, or people, companies or jobs similar to the one you send. "result" counts each one. "page of 50" counts each page, and you pay for a whole page even when it holds fewer than 50. `resultsPerPage` is the most a page holds, or `null`. "page, size not stated" means the provider doesn't say how many a page holds. |
| `costUnits` | number, or empty | The plan's units one call costs, counted in `unit`: 1 for a call at one credit, 0 for a free call, like a call on a flat fee. On a plan that charges by the result or the page, the units one result or page costs, as `per` says. Null when the provider doesn't list the cost. |
| `resultsCap` | number or text, or empty | For a search API, the most results you can get from one search on this plan, however many pages you ask for. "no limit" when the provider says you can get every match. Blank (`null` in the JSON) when the provider's docs don't say, or when the API isn't a search. |
| `extras` | list | Fields that cost more. Each has its `fields` and its `perThousand` on top of the row's. |
| `alsoPaysFor` | list, or empty | The other calls you get for the plan's price, each with its own limit, in the provider's words. We leave out apps, extensions, MCP servers, proxies and storage, and what you can do only in the provider's app, like sending its email campaigns: they are not calls. For an account's price, gtm-api.com also gives you 100 searches, 50 messages and 25 connection requests a day. "nothing" when you get only the profile call. The row's $ per 1,000 is for the profile call alone, since no provider says how to split its price. Blank (`null` in the JSON) until we read the provider's plan, and on a "contact" plan whose pages don't say what its price buys, like its Pay. |
| `sharesBudgetWith` | list, or empty | The other calls that spend the same credits or limit as the profile call, like gtm-api.com's company and post reads. We leave out apps and MCP servers, which are not calls. We work out the row's $ per 1,000 as if you make none of these calls. "nothing" when no other call shares the budget. On the sheet, the Also pays for column lists them last, after "from the same budget". Blank (`null` in the JSON) until we check which calls share the budget, and on a "contact" plan whose pages don't say. |
| `perDay` | number, or empty | The most calls a day. |
| `perSecond` | number, or empty | The most calls a second you can keep up. When the provider counts a limit over a longer window, we divide it: a limit per minute by 60, per 5 minutes by 300, per hour by 3,600. When it sets several, we show the tightest: 25 a second and 40 a minute is 0.67. We round it to two decimals, and a rate under 0.1 to two digits past its zeros: 5 an hour is 0.0014. |
| `concurrent` | number or text, or empty | The most calls running at once, or "no limit". "n/a" when the provider sets no cap on calls at once but limits them by the second: its "Per second" limits you. Blank (null) when the provider's pages don't say. |
| `batch` | number or text, or empty | The most profile URLs, people, emails, phones, companies, posts or searches one call takes on this plan. 1 when it takes one at a time. "no limit" when the provider says a call takes any number. Blank (null) when a call takes a list and the provider's pages don't say how long. |
| `answer` | text | How the call's answer comes back. "in the call" when its response holds it. "by polling or webhook" when the call returns a job, and you get the profile from another call once the job is done, or at your webhook. "in the call or by polling" when the call answers if the result is ready in time, and otherwise hands back a job to call for later, like an Apify Actor past 5 minutes. "in the call or by webhook" when you choose in your request. "by polling" when only another call reads it, "by webhook" when only a URL you give gets it. Blank (null) when the provider's pages don't say. |
| `latencyMs` | number, or empty | The median time a call takes. If we benchmarked the row's call, we show our benchmark's median, as on the API's benchmark page: each call's time minus the mean time of three free calls to the same provider before it. If that mean is longer than the call, we use the provider's median baseline, capped at the call's time, so no time is below zero. For other rows, it is the time the provider's pages give, or one we measured when we added the row. Blank (null) when we have neither. Milliseconds in the JSON and datacircle.csv, seconds on the sheet and in its CSV. |
| `fields` | list | The fields the answer can hold at the row's price, each when the provider has it. We count each field once. A list counts once, and so does each field in it: jobs, job title and job company are three fields. We count this way for every provider. Under Filters, Must return keeps the rows whose answer can hold every field you tick, at the row's price. |
| `completeness` | number | The share of its API's key fields the answer holds, out of 100, including the ones you pay an extra field for, as the plan's page shows it. Key fields, below, lists them. Only datacircle.json and datacircle.csv have it. |
| `keyFields` | list | The key fields of its API the answer holds at the row's price, as the plan's page names them, like "Experience" or "Skills". A key field the answer holds in part, like only the top skills, is in the list too. Only datacircle.json and datacircle.csv have it. |
| `extraKeyFields` | list | The key fields of its API you get only when you pay for an extra field (`extras`). Only datacircle.json and datacircle.csv have it. |
| `send` | text | What you give the call: a profile URL, a person's name and company, a person's ID, an email, a phone number, a company's LinkedIn URL, domain, name or ID, a post's URL or ID, or search filters. The call needs the inputs before "Optional:". The optional ones come after it, or after a semicolon in the CSV and the JSON. |
| `call` | text, or empty | The call's name, as the provider's docs title it, when the provider sells more than one call for the API, like LinkFinder AI's lead_full_name_to_email and linkedin_profile_to_email, both POST /. Blank (`null` in the JSON) when it sells one. |
| `method` | text | The call's HTTP method. |
| `path` | text | The call's path, as in the provider's docs: the same on each plan of a call, unless the provider serves a plan at its own address. |
| `docs` | text | The provider's page for the call. |
| `readFrom` | list | The pages we read the row's values from. They are the sheet's last column: click a cell to see each page, or press ⌘C to copy them all. |
| `checked` | text | The day we last read every value on those pages, California time. |

The APIs, the values of `api`, with the sheet each is on:

| `api` | `category` › `subcategory` › `sheet` |
|---|---|
| Employee profile | People › Profiles › LinkedIn profiles |
| Person enrichment | People › Profiles › Person enrichment |
| Employee lookalikes | People › Profiles › Similar people |
| Employee recommendations | People › Profiles › LinkedIn person recommendations |
| Employee search | People › Search › LinkedIn people search |
| People search | People › Search › People search |
| Employee email | Contact › Email › Find email |
| Email validation | Contact › Email › Validate email |
| Reverse email lookup | Contact › Email › Reverse email lookup |
| Employee phone | Contact › Phone › Find phone |
| Phone validation | Contact › Phone › Validate phone |
| Company profile | Companies › Profiles › LinkedIn company profiles |
| Company enrichment | Companies › Profiles › Company enrichment |
| Company technologies | Companies › Profiles › Company technologies |
| Company hierarchy | Companies › Profiles › Company hierarchy |
| Company search | Companies › Search › LinkedIn company search |
| Company discovery | Companies › Search › Company discovery |
| Company lookalikes | Companies › Search › Similar companies |
| Job search | Signals › Hiring › LinkedIn job search |
| Job postings | Signals › Hiring › Job postings |
| Job details | Signals › Hiring › LinkedIn job details |
| Job posting details | Signals › Hiring › Job posting details |
| Job lookalikes | Signals › Hiring › Similar jobs |
| Company jobs | Signals › Hiring › Company open jobs |
| Company job count | Signals › Hiring › Company job count |
| Leadership changes | Signals › Hiring › Leadership changes |
| Post search | Signals › Engagement › LinkedIn post search |
| Post details | Signals › Engagement › LinkedIn post details |
| Employee posts | Signals › Engagement › LinkedIn person posts |
| Employee articles | Signals › Engagement › LinkedIn person articles |
| Company posts | Signals › Engagement › LinkedIn company posts |
| Post comments | Signals › Engagement › LinkedIn post comments |
| Post reactions | Signals › Engagement › LinkedIn post reactions |
| Post reposts | Signals › Engagement › LinkedIn post reposts |
| Employee comments | Signals › Engagement › LinkedIn person comments |
| Employee reactions | Signals › Engagement › LinkedIn person reactions |
| Company headcount | Signals › Growth › Company headcount |
| Company funding | Signals › Growth › Company funding |

## 3. Query it

DuckDB reads the JSON and the CSV as they are, with no setup:

```bash
duckdb -c "SELECT provider, plan, billing, pay, perThousand, score, page FROM 'datacircle.json' WHERE api = 'Employee email' AND pay > 0 AND pay <= 50 AND perThousand IS NOT NULL ORDER BY perThousand LIMIT 10"
```

The best scored plans of an API, with each part of the score:

```sql
SELECT provider, plan, score, priceScore, dataScore, costToGetStartedScore, bundleScore, performanceScore
FROM 'datacircle.json' WHERE api = 'Employee profile' AND score IS NOT NULL ORDER BY score DESC LIMIT 10;
```

Every plan of one provider:

```sql
SELECT api, plan, billing, pay, perThousand FROM 'datacircle.json' WHERE provider ILIKE '%fetchin%' ORDER BY api, perThousand;
```

The cheapest paid plan per 1,000 of each API:

```sql
SELECT api, arg_min(provider || ', ' || plan, perThousand) AS plan, min(perThousand) AS perThousand
FROM 'datacircle.json' WHERE pay > 0 AND perThousand IS NOT NULL GROUP BY api ORDER BY api;
```

Without DuckDB, with jq:

```bash
jq '[.[] | select(.api == "Employee email" and .pay > 0 and .pay <= 50 and .perThousand != null)] | sort_by(.perThousand) | .[:10] | map({provider, plan, pay, perThousand, score, page})' datacircle.json
```

Or Python:

```python
import json
rows = json.load(open("datacircle.json"))
found = sorted((r for r in rows if r["api"] == "Employee email" and r["perThousand"] is not None), key=lambda r: r["perThousand"])
```

Each row's `page` is its plan's page on datacircle.dev, and `docs` the provider's own page for the call. Give your user those links with what you found. Every key is also explained at https://datacircle.dev/fields, and the docs are at https://datacircle.dev/docs.

## Limitations

- Empty (`null` in the JSON) means the provider's pages don't say, or the key doesn't apply to that row.
- We update the file each time we update the site, so download it again when your copy is more than a day old.
