A JSON kind maps to a component per template: split is CodeSplit on a product, UseCaseSplit on a use case, HubSplit on a hub.
The production components, fed with the site’s own data
49 sections in 8 groups. Each one is the real component, rendered full width with the JSON of a real page, so what you see here is what ships. The card above each specimen says which file renders it, which JSON kind produces it, which templates call it and what it requires.
A missing asset or href switches a component to a degraded variant without an error. The contract lists what each one requires.
Every section carries its .container and its padding-top. Nothing here is wrapped, so the geometry is the one of the live page.
A rail, a matrix or a split follows a grid. Two consecutive grids read as one long grid.
Heroes: one per template, never two on a page
Four heroes, one H1 each. The framed hero carries a MotionScene in its proof frame; the centered heroes carry copy and two CTAs.
ProductHero
components/product/ProductHero.astroThe centered product hero: tag, H1 with an accent segment, subtitle, two buttons. No KPI band below it since the September build (the stats field of the JSON is dormant).
Notputting a proof frame in it. A product opens on its logos band, the proof comes with the first section.
Any market, mapped
Company search API with custom targeting
Search companies by industry, size, location, keywords, revenue, web traffic, SIC/NAICS codes, and signals to build smarter account lists.
JSON · content/products/company-search.json › hero
{
"tag": "Any market, mapped",
"h1": "Company search API with **custom targeting**",
"subtitle": "Search companies by industry, size, location, keywords, revenue, web traffic, SIC/NAICS codes, and signals to build smarter account lists.",
"primaryCta": {
"label": "Get 1,000 free records",
"href": "https://app.blitz-api.ai"
},
"secondaryCta": {
"label": "API Docs",
"href": "https://docs.blitz-api.ai/api-reference/company-search/company-search"
}
}UseCaseHero
components/usecase/UseCaseHero.astroThe framed hero (top border, hero, bottom border) with the MotionScene of the slug in its proof frame. Framed pages are the playbook pages.
Notrendering it without a scene: the media zone stays empty and the hero becomes a centered text block.
Build your TAM with B2B data
Create target account lists using company filters, job signals, enrichment, and decision-maker discovery from one API infrastructure.
BUILD TAMJSON · content/use-cases/build-tam.json › hero (+ specs/use-cases/build-tam.json)
{
"tag": "By use case",
"h1": "Build your TAM with **B2B data**",
"subtitle": "Create target account lists using company filters, job signals, enrichment, and decision-maker discovery from one API infrastructure.",
"primaryCta": {
"label": "Start building",
"href": "https://app.blitz-api.ai"
},
"secondaryCta": {
"label": "Contact us",
"href": "/contact"
}
}PersonaHero
components/persona/PersonaHero.astroThe persona hero: « B2B data APIs for » on one line, the persona in accent on the next.
B2B data APIs for
GTM Engineers
Use BlitzAPI to create search, enrichment, validation, and signal workflows directly inside your GTM stack.
JSON · content/teams/gtm-engineers.json › hero
{
"tag": "Built for GTM Engineers",
"h1": "B2B data APIs for GTM Engineers",
"subtitle": "Use BlitzAPI to create search, enrichment, validation, and signal workflows directly inside your GTM stack.",
"primaryCta": {
"label": "Get 1,000 free records",
"href": "https://app.blitz-api.ai"
},
"secondaryCta": {
"label": "Contact us",
"href": "/contact"
}
}PageHero
components/sections/PageHero.astroThe standard hero of internal pages when there is no product, playbook or persona to frame.
Notthe left variant with a bare .container: it carries the section envelope geometry (--container-inner + --pad-inner-s), otherwise its text sits on the left rail.
Same possibilities.
Different scales.
One API key, the whole data layer: companies, people, verified emails, phone numbers and job postings. Plans differ by speed, fair use policy and support, never by data.
Astro · pricing.astro
<PageHero tag={COPY.hero.tag} h1={COPY.hero.h1} subtitle={COPY.hero.subtitle} align="center" compact />The bands that pace the page
Trust, logos, the hatched divider, the offer, the signed conversion band. They are shared by every directory and never redrawn locally.
TrustedBand (product)
components/product/TrustedBand.astroThe « Trusted by the best GTM teams » band right under a product hero. 130px, uniform on the 15 products.
Trusted by the best GTM teams














Astro
<TrustedBand /> {/* components/product/TrustedBand.astro */}TrustedBand (use case)
components/usecase/TrustedBand.astroThe same trust signal for the framed pages: a centered hook instead of the bordered cell.
Trusted by the best GTM teams














Astro
<TrustedBand /> {/* components/usecase/TrustedBand.astro */}LogoBand
components/sections/LogoBand.astroThe client marquee alone, for pages whose hero already carries its own proof.














Astro
<LogoBand />SectionDivider
components/sections/SectionDivider.astroThe hatched band that separates the opening from the body, and the body from the closing. 92 → 60 → 50 → 44px across the breakpoints.
Notcompensating the next section by adjacency (:global(.A + .B)): those rules were dead in the cascade on 15 pages.
Astro
<SectionDivider />OfferBand
components/sections/OfferBand.astroThe pricing anchor: the strip states the entry price before a decision on landing pages. The band variant left the home on 2026-10-14 and is kept for a future page. No date.
Notwriting a figure in the component or the JSON. The offer changes in one file.
PRICING
Every endpoint, on every plan.
Start at $99 a month with 10 requests per second per endpoint. Scale to $499 for 25 requests per second per endpoint and a fair use policy 25 times higher. Beyond that, Build Your Infra is fully custom.
1,000 FREE RECORDS, NO CARD
Astro
<OfferBand variant="strip" href="/pricing" /> {/* directory pages, before the CTA */}
<OfferBand variant="band" /> {/* home */}SignatureBand
components/sections/SignatureBand.astroThe signed conversion band before the FAQ: one brand signature per family, a line, the button to the API docs.
TS · config/signature-bands.ts › FAMILY_BANDS.search
{
"signature": "cascade",
"eyebrow": "SEARCH & DISCOVERY",
"text": "Every search endpoint shares the same filters, the same pagination, and the same response shape."
}
<SignatureBand {...FAMILY_BANDS[data.family]} href={data.docsUrl} />Text on the rail, proof on the side
A split develops one argument. The column scale descends (title 28, intro 18, bullets 16), the CTA sits on a rule, and the proof frame carries one asset.
FeatureLead
components/product/FeatureLead.astrokind: features (first section)The editorial opening of a page that has no split: a lead column and a numbered list of capabilities with their asset. A page never opens on a grid.
Nota features section later in the page: from position 2 on, features render as GrayCards.
A record built like an API response, not a copy of a profile page
A profile URL is the smallest honest input in B2B data: no name collisions, no domain guessing, exactly one person.
Typed fields, not text blobs
Experience comes back as experiences[], one object per position with start and end dates, a job_is_current flag, the job description and the work location. Education, skills and certifications are arrays you can map straight into a schema. Nothing left to parse.
Current by design
The record reflects where the person works now. Job changes are detected, and stale records are removed from live circulation, so yesterday's title does not ship as today's answer.
Keys that survive your joins
The record carries the person's canonical LinkedIn URL, and every position carries the employer's LinkedIn URL, LinkedIn ID and domain: stable handles for resolving the same person and the same company across a CRM, a warehouse and a vendor export, however differently each of them spells the name.
An output that chains
This is the profile-first counterpart to the reverse lookups: use it when you already hold a LinkedIn URL and want the whole career, not a single contact point. Pass the same URL to Email Enrichment or Phone Enrichment when you also need a way to reach the person.
JSON · content/products/profile-enrichment.json › sections[0] (features)
{
"kind": "features",
"title": "A record built like an API response, not a copy of a profile page",
"subtitle": "A profile URL is the smallest honest input in B2B data: no name collisions, no domain guessing, exactly one person.",
"items": [
{
"title": "Typed fields, not text blobs",
"text": "Experience comes back as experiences[], one object per position with start and end dates, a job_is_current flag, the job description and the work location. Education, skills and certifications are arrays you can map straight into a schema. Nothing left to parse.",
"asset": "json-object"
},
{
"title": "Current by design",
"text": "The record reflects where the person works now. Job changes are detected, and stale records are removed from live circulation, so yesterday's title does not ship as today's answer.",
"asset": "person-record"
},
{
"title": "Keys that survive your joins",
"text": "The record carries the person's canonical LinkedIn URL, and every position carries the employer's LinkedIn URL, LinkedIn ID and domain: stable handles for resolving the same person and the same company across a CRM, a warehouse and a vendor export, however differently each of them spells the name.",
"asset": "resolver"
},
{
"title": "An output that chains",
"text": "This is the profile-first counterpart to the reverse lookups: use it when you already hold a LinkedIn URL and want the whole career, not a single contact point. Pass the same URL to Email Enrichment or Phone Enrichment when you also need a way to reach the person.",
"asset": "enrichment-chain"
}
]
}CodeSplit
components/product/CodeSplit.astrokind: splitThe product overview: eyebrow, accented title, vertical-bar bullets, the API Docs button, and the dark panel that receives the asset.
Notchanging the 72px before the button or the 556×448 panel: the hubs share these values, changing them misaligns the site.
Search
Explore any market with custom targeting
Search companies by firmographics, location, keywords, traffic, revenue, ad activity, and signals to build smarter account lists from one request.
Search companies by industry, size, location, and keywords
Build TAMs and ABM lists from custom targeting
JSON · content/products/company-search.json › sections[0] (split)
{
"kind": "split",
"title": "Explore any market with custom targeting",
"subtitle": "Search companies by firmographics, location, keywords, traffic, revenue, ad activity, and signals to build smarter account lists from one request.",
"asset": "search-query",
"items": [
{
"text": "Search companies by industry, size, location, and keywords"
},
{
"text": "Build TAMs and ABM lists from custom targeting"
}
]
}ProductTabs
components/product/ProductTabs.astrokind: showcaseSeveral capabilities of one API, one at a time, without replacing the explanation with a big product capture.
From company search to market intelligence
Define markets
Build precise company universes. Start with any market and narrow it using company size, industry, location, keywords, revenue, web traffic, ad spend, SIC codes, or NAICS codes.
Detect signals
Find companies showing movement. Use company data and market signals to identify accounts that are growing, investing, hiring, advertising, or moving into a new phase.
Build lists
Turn targeting into account lists. Create clean company datasets for outbound, ABM, territory planning, CRM enrichment, or market mapping without starting from static databases.
JSON · content/products/company-search.json › sections[1] (showcase)
{
"kind": "showcase",
"title": "From company search to **market intelligence**",
"items": [
{
"title": "Define markets",
"text": "Build precise company universes. Start with any market and narrow it using company size, industry, location, keywords, revenue, web traffic, ad spend, SIC codes, or NAICS codes.",
"asset": "filter-set"
},
{
"title": "Detect signals",
"text": "Find companies showing movement. Use company data and market signals to identify accounts that are growing, investing, hiring, advertising, or moving into a new phase.",
"asset": "signal"
},
{
"title": "Build lists",
"text": "Turn targeting into account lists. Create clean company datasets for outbound, ABM, territory planning, CRM enrichment, or market mapping without starting from static databases.",
"asset": "dataset",
"assetValue": "65M+",
"assetLabel": "COMPANIES"
}
]
}UseCaseSplit
components/usecase/UseCaseSplit.astrokind: splitThree variants derived from the content, never chosen by a prop: bullets, conversion band, showcase. The second split of a use case is the conversion band.
Nota second split without an href item: it silently falls back to « points » and the page shows two rows of the same shape.
Create target account lists from better data
Build a TAM that your sales and growth teams can actually use: filtered, enriched, prioritized, and ready for CRM or outbound workflows.
Build a TAM your team can actually use
A static company list is not enough. BlitzAPI helps you create a target account market using company data, hiring signals, enrichment, and decision-maker discovery, so your team can focus on the accounts most likely to matter.
JSON · content/use-cases/build-tam.json › sections[0] and sections[3] (split)
{
"kind": "split",
"title": "Create target account lists **from better data**",
"subtitle": "Build a TAM that your sales and growth teams can actually use: filtered, enriched, prioritized, and ready for CRM or outbound workflows.",
"asset": "filter-set",
"items": [
{
"text": "Identify companies that match your ICP."
},
{
"text": "Add job and growth signals to your TAM."
},
{
"text": "Prioritize accounts before outreach."
}
]
}
{
"kind": "split",
"title": "Build a TAM your team can actually use",
"subtitle": "A static company list is not enough. BlitzAPI helps you create a target account market using company data, hiring signals, enrichment, and decision-maker discovery, so your team can focus on the accounts most likely to matter.",
"asset": "gtm-loop",
"items": [
{
"title": "Start building your TAM",
"href": "https://app.blitz-api.ai"
}
]
}HubSplit
components/hub/HubSplit.astrokind: splitThe editorial split of the two hubs, extracted from CodeSplit: same geometry, a proof frame with a head and a foot line.
AI-native tooling
BlitzAPI inside your AI tools
The BlitzAPI MCP server gives Claude, Cursor or VS Code one tool per API endpoint, the documentation and built-in GTM skills. Ask for data in a chat, or have your assistant write the script that pulls it: same endpoints, same parameters, same responses.
MCP server URL
Plug https://api.blitz-api.ai/mcp into Claude, Cursor, VS Code or any MCP-compatible tool, then sign in with your BlitzAPI account or send your API key.
Fewer hallucinations
Your assistant reads the actual API reference before it calls an endpoint, instead of guessing endpoints and parameter names.
JSON · data/pages/developers.json › split
{
"kind": "split",
"eyebrow": "AI-native tooling",
"title": "BlitzAPI inside your **AI tools**",
"subtitle": "The BlitzAPI MCP server gives Claude, Cursor or VS Code one tool per API endpoint, the documentation and built-in GTM skills. Ask for data in a chat, or have your assistant write the script that pulls it: same endpoints, same parameters, same responses.",
"items": [
{
"text": "Plug https://api.blitz-api.ai/mcp into Claude, Cursor, VS Code or any MCP-compatible tool, then sign in with your BlitzAPI account or send your API key."
},
{
"text": "Your assistant reads the actual API reference before it calls an endpoint, instead of guessing endpoints and parameter names."
},
{
"title": "BlitzAPI MCP server",
"href": "/mcp"
},
{
"title": "MCP setup guide",
"href": "https://docs.blitz-api.ai/guide/integrations/MCP"
}
],
"asset": "terminal-command",
"proof": {
"head": "BLITZAPI → YOUR AI TOOLS",
"status": "LIVE",
"label": "api.blitz-api.ai/mcp",
"alt": "Terminal command adding the BlitzAPI MCP server to an AI tool",
"foot": "ONE TOOL PER ENDPOINT · DOCS · SKILLS"
}
}One grammar of destination cells
Equal cells, 1px rules drawn by the gap, the destination type in mono deduced from the href by one shared table (lib/destination.ts, no fallback label), arrow visible at rest, whole cell clickable. No text block is vertically centered.
GrayCards
components/product/GrayCards.astrokind: features · usecases · apis · stepsThe gray cards (surface-alt, radius 4px) shared by three roles: capabilities, destinations with a rolling « Learn more », numbered steps.
Nottwo card bands in a row. A rail or a matrix replaces the second one.
Built for smarter account discovery
Explore markets, identify high-fit accounts, and use signals to prioritize where your team should focus first.
Explore markets
Search any segment by combining firmographic, geographic, keyword, traffic, revenue, and classification filters.
Prioritize accounts
Use signals like growth, hiring, traffic, ad activity, and ICP fit to focus on companies with stronger potential.
Build workflows
Turn company results into people search, enrichment, validation, CRM sync, ABM, or outbound workflows.
Related APIs
Company Search API
Search and discover companies by industry, size, location, keywords, and signals. Build markets, identify accounts, and create better prospecting workflows.
Profile Enrichment API
Turn one LinkedIn profile URL into the complete person record: typed JSON with headline, location, each role and its employer identifiers, education and skills.
From URL to typed record
One endpoint, POST /v2/enrichment/person (Person Enrichment in the API reference), turns a profile link into structured JSON.
Send the URL
POST the person's LinkedIn URL as person_linkedin_url. That is the whole request body; no name, no company, no guessing on your side.
We resolve the person
The URL is matched against 550M+ profiles. Every response carries found: on true, person holds the full profile; on false, person is null and nothing is counted.
Read the record
The full record lands in typed fields: identity, headline, about, location and connections count, then experiences[], education[], skills[] and certifications[], each one ready to map into a schema.
Write it back, or chain it
Pass the LinkedIn URL straight into email or phone enrichment, or write the record back to your CRM and join on the employer identifiers carried by each position.
JSON · content/products/company-search.json › features (plain) · relatedProducts (links) · steps (numbered)
{
"kind": "features",
"title": "Built for smarter account **discovery**",
"subtitle": "Explore markets, identify high-fit accounts, and use signals to prioritize where your team should focus first.",
"items": [
{
"title": "Explore markets",
"text": "Search any segment by combining firmographic, geographic, keyword, traffic, revenue, and classification filters.",
"icon": "/icons/Work-Flow.svg",
"asset": "filter-set"
},
{
"title": "Prioritize accounts",
"text": "Use signals like growth, hiring, traffic, ad activity, and ICP fit to focus on companies with stronger potential.",
"icon": "/icons/Data.svg",
"asset": "icp-score"
},
{
"title": "Build workflows",
"text": "Turn company results into people search, enrichment, validation, CRM sync, ABM, or outbound workflows.",
"icon": "/icons/Design.svg",
"asset": "router"
}
]
}
// links: Related APIs, derived from relatedProducts[]
[
{
"title": "Company Search API",
"text": "Search and discover companies by industry, size, location, keywords, and signals. Build markets, identify accounts, and create better prospecting workflows.",
"href": "/products/company-search"
},
{
"title": "Profile Enrichment API",
"text": "Turn one LinkedIn profile URL into the complete person record: typed JSON with headline, location, each role and its employer identifiers, education and skills.",
"href": "/products/profile-enrichment"
}
]PlaybookGrid
components/usecase/PlaybookGrid.astrokind: featuresThe capability map: a closed matrix where every cell is a destination, its type in mono deduced from the href.
Built for every data workflow
Everything required to discover companies, identify buyers, enrich records, detect signals, and activate data from a single infrastructure layer.
JSON · content/use-cases/build-tam.json › sections[2] (features)
{
"kind": "features",
"title": "Built for every **data workflow**",
"subtitle": "Everything required to discover companies, identify buyers, enrich records, detect signals, and activate data from a single infrastructure layer.",
"items": [
{
"title": "Build TAM",
"text": "Create dynamic markets using companies, people, jobs and signals.",
"href": "/use-cases/build-tam"
},
{
"title": "Find Decision Makers",
"text": "Identify decision makers and key stakeholders across every account.",
"href": "/use-cases/find-decision-makers"
},
{
"title": "Jobs Intelligence",
"text": "Turn millions of job postings into signals and market intelligence.",
"href": "/products/jobs-search"
},
{
"title": "Enrich Records",
"text": "Transform incomplete records into complete, actionable profiles.",
"href": "/use-cases/profile-enrichment"
},
{
"title": "Identity Resolution",
"text": "Resolve domains, emails, LinkedIn URLs, and matching keys across fragmented datasets.",
"href": "/use-cases/data-resolution"
},
{
"title": "AI-Native Infrastructure",
"text": "Plug agents and AI workflows into the data layer through the MCP server, Skills and typed SDKs.",
"href": "/developers"
}
]
}ConnectorMatrix
components/hub/ConnectorMatrix.astrokind: showcaseThe orchestration tools that call BlitzAPI. GUIDE cells link, HTTP MODULE cells say the truth.
Works with your stack
The tools your team already uses, one data engine behind them.
JSON · data/pages/integrations.json › showcase
{
"kind": "showcase",
"title": "Works with **your stack**",
"subtitle": "The tools your team already uses, one data engine behind them.",
"linkLabel": "Guide",
"items": [
{
"title": "Clay",
"text": "Paste a cURL command into Clay's HTTP API column and build high-volume enrichment waterfalls in Clay without writing code.",
"href": "https://docs.blitz-api.ai/guide/integrations/clay",
"logo": "clay"
},
{
"title": "n8n",
"text": "Chain waterfall search, lead enrichment, and CRM sync into autonomous n8n workflows with the HTTP Request node.",
"href": "https://docs.blitz-api.ai/guide/integrations/n8n",
"logo": "n8n"
},
{
"title": "Make",
"text": "Add BlitzAPI to thousands of app scenarios with the HTTP module: Airtable, HubSpot, Google Sheets, and more.",
"href": "https://docs.blitz-api.ai/guide/integrations/make",
"logo": "make"
},
{
"title": "Zapier",
"text": "Trigger enrichment from any Zap with a webhook step and write results back to your connected apps.",
"logo": "zapier"
},
{
"title": "Airtable",
"text": "Enrich bases with company, contact, and email data through automations or your orchestration tool of choice.",
"logo": "airtable"
},
{
"title": "Google Sheets",
"text": "Turn spreadsheets into enrichment pipelines via Make, n8n, or a simple script.",
"logo": "google-sheets"
},
{
"title": "HubSpot",
"text": "HubSpot data enrichment on workflow triggers: refresh company records, add decision makers, and re-verify emails.",
"logo": "hubspot"
},
{
"title": "Salesforce",
"text": "Power flows and buttons with live enrichment: resolve, refresh, and complete records on demand.",
"logo": "salesforce"
},
{
"title": "Pipedrive",
"text": "Keep deals moving with enriched organizations and verified contact data.",
"logo": "pipedrive"
},
{
"title": "Smartlead",
"text": "Feed campaigns with validated emails and enriched personalization fields.",
"logo": "smartlead"
},
{
"title": "Instantly",
"text": "Load clean, verified prospect lists straight into your sending infrastructure.",
"logo": "instantly"
},
{
"title": "Lemlist",
"text": "Launch campaigns on enriched contacts with emails checked before the first send.",
"logo": "lemlist"
}
]
}UseCaseRail
components/sections/UseCaseRail.astrokind: usecases · showcaseThe editorial rail: one full row per destination instead of a second grid of cards.
What teams build with Company Search
JSON · content/products/company-search.json › usecases
{
"kind": "usecases",
"title": "What teams build with Company Search",
"items": [
{
"title": "Decision Makers Identification",
"text": "Find the right people inside target accounts and map the stakeholders who matter most.",
"href": "/use-cases/find-decision-makers"
},
{
"title": "Build TAM",
"text": "Create dynamic target markets by combining company data, people data, jobs, and signals.",
"href": "/use-cases/build-tam"
},
{
"title": "Data Resolution & Matching",
"text": "Connect company names, domains, LinkedIn URLs, websites, and identifiers into cleaner datasets.",
"href": "/use-cases/data-resolution"
},
{
"title": "For Revenue Teams",
"text": "Give revenue teams one data layer to find, enrich, and activate their next best accounts.",
"href": "/teams/revops"
}
]
}WorkflowSteps
components/sections/WorkflowSteps.astrokind: stepsA sequence on a rail, numbered. The one component every template shares for « how it works ».
From URL to typed record
One endpoint, POST /v2/enrichment/person (Person Enrichment in the API reference), turns a profile link into structured JSON.
Send the URL
POST the person's LinkedIn URL as person_linkedin_url. That is the whole request body; no name, no company, no guessing on your side.
We resolve the person
The URL is matched against 550M+ profiles. Every response carries found: on true, person holds the full profile; on false, person is null and nothing is counted.
Read the record
The full record lands in typed fields: identity, headline, about, location and connections count, then experiences[], education[], skills[] and certifications[], each one ready to map into a schema.
Write it back, or chain it
Pass the LinkedIn URL straight into email or phone enrichment, or write the record back to your CRM and join on the employer identifiers carried by each position.
JSON · content/products/profile-enrichment.json › steps
{
"kind": "steps",
"title": "From URL to typed record",
"subtitle": "One endpoint, POST /v2/enrichment/person (Person Enrichment in the API reference), turns a profile link into structured JSON.",
"items": [
{
"title": "Send the URL",
"text": "POST the person's LinkedIn URL as person_linkedin_url. That is the whole request body; no name, no company, no guessing on your side."
},
{
"title": "We resolve the person",
"text": "The URL is matched against 550M+ profiles. Every response carries found: on true, person holds the full profile; on false, person is null and nothing is counted."
},
{
"title": "Read the record",
"text": "The full record lands in typed fields: identity, headline, about, location and connections count, then experiences[], education[], skills[] and certifications[], each one ready to map into a schema."
},
{
"title": "Write it back, or chain it",
"text": "Pass the LinkedIn URL straight into email or phone enrichment, or write the record back to your CRM and join on the employer identifiers carried by each position."
}
]
}RelatedApis
components/usecase/RelatedApis.astrokind: apis · usecasesThe endpoints that execute the playbook: title and proof on the left, every endpoint unfolded on the right.
Notan accordion. Below six entries everything is unfolded, and the destination link exists at rest.
JSON · content/use-cases/build-tam.json › apis (+ UC_META endpoint)
{
"kind": "apis",
"title": "APIs that power this playbook",
"asset": "dataset",
"items": [
{
"title": "Company Search",
"text": "Search by industry, size, country, keywords, and market filters.\nCreate clean company lists from your ICP criteria.\nUse results as the foundation for enrichment and scoring.",
"href": "/products/company-search"
},
{
"title": "Jobs Signal",
"text": "Track jobs by company and month.\nFilter by job title, description, location, and date posted.\nSpot growth, expansion, and team-building signals.",
"href": "/products/jobs-signal"
},
{
"title": "Waterfall ICP",
"text": "Search each account with your ICP hierarchy.\nReturn the best available decision maker first.\nSend matched contacts to enrichment or outbound.",
"href": "/products/waterfall-icp"
}
]
}CodeTabs
components/hub/CodeTabs.astrokind: codeThe same call in cURL, Python and TypeScript, or the same server set up in each client. A developers page shows code.
Nota snippet without a source URL: the surface of an SDK is not deduced by analogy.
First call
The same call, three ways
A LinkedIn profile URL in, a verified work email out. Same endpoint, same parameters, same response. You pick the interface, not the API.
curl -X POST https://api.blitz-api.ai/v2/enrichment/email \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"person_linkedin_url":"https://www.linkedin.com/in/example-person"}'from blitz_api import BlitzAPI
client = BlitzAPI() # reads BLITZ_API_KEY
email = client.enrichment.email(
person_linkedin_url="https://www.linkedin.com/in/example-person"
)
if email.found:
print(email.email)import { BlitzAPI } from "blitz-api-js";
const client = new BlitzAPI(); // reads BLITZ_API_KEY
const email = await client.enrichment.email({
person_linkedin_url: "https://www.linkedin.com/in/example-person",
});
if (email.found) console.log(email.email);foundemailall_emails[]JSON · data/pages/developers.json › code
{
"kind": "code",
"eyebrow": "First call",
"title": "The same call, **three ways**",
"subtitle": "A LinkedIn profile URL in, a verified work email out. Same endpoint, same parameters, same response. You pick the interface, not the API.",
"method": "POST",
"endpoint": "/v2/enrichment/email",
"responseFields": [
"found",
"email",
"all_emails[]"
],
"items": [
{
"title": "cURL",
"source": "https://docs.blitz-api.ai/api-reference/people-enrichment/find-work-email",
"code": "curl -X POST https://api.blitz-api.ai/v2/enrichment/email \\\n -H \"x-api-key: YOUR_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"person_linkedin_url\":\"https://www.linkedin.com/in/example-person\"}'"
},
{
"title": "Python",
"source": "https://docs.blitz-api.ai/sdks/python",
"code": "from blitz_api import BlitzAPI\n\nclient = BlitzAPI() # reads BLITZ_API_KEY\n\nemail = client.enrichment.email(\n person_linkedin_url=\"https://www.linkedin.com/in/example-person\"\n)\nif email.found:\n print(email.email)"
},
{
"title": "TypeScript",
"source": "https://docs.blitz-api.ai/sdks/typescript",
"code": "import { BlitzAPI } from \"blitz-api-js\";\n\nconst client = new BlitzAPI(); // reads BLITZ_API_KEY\n\nconst email = await client.enrichment.email({\n person_linkedin_url: \"https://www.linkedin.com/in/example-person\",\n});\nif (email.found) console.log(email.email);"
}
]
}McpTools
components/mcp/McpTools.astrokind: tools (root field of data/pages/mcp.json)The reference sheet of an MCP server: one row per tool, grouped by prefix like the docs, the tool name and the endpoint it calls in mono, then the name and what goes in and comes back. The grammar of EndpointToolkit (framed sheet, h3 family labels, stretched name link), with its own contract because most rows are not product pages.
Notstretching EndpointToolkit to it: the five team pages rely on its 4 to 8 product-only rows.
One tool per endpoint
Tools are named after what they return, and each API tool runs exactly one endpoint: what the API reference says about a parameter or a response applies unchanged.
- Tools
- 16
- API endpoints
- 16
People
people_searchPOST/v2People Search API Title, level, function and company filters in, matching people across companies out./search /people people_employee_finderPOST/v2Employee Finder API A company in, its current employees by level, function and country out./search /employee-finder people_waterfall_icpPOST/v2Waterfall ICP API A company and ranked title tiers in, the best-placed people out, tier by tier./search /waterfall-icp-keyword people_enrichPOST/v2Profile Enrichment API A profile URL in, the person and their whole career out./enrichment /person people_find_work_emailPOST/v2Email Enrichment API A profile URL in, the verified work email out, or Not Found instead of a guess./enrichment /email people_find_phonePOST/v2Phone Enrichment API A profile URL in, mobile and direct US phone numbers out./enrichment /phone people_lookup_by_emailPOST/v2Reverse Email Lookup API An email address in, the professional profile behind it out./enrichment /email-to-person people_lookup_by_phonePOST/v2Reverse Phone Lookup API A phone number in, the professional profile behind it out./enrichment /phone-to-person
Companies
company_searchPOST/v2Company Search API Industry, size, location and funding filters in, matching companies out./search /companies company_enrichPOST/v2Company Enrichment API A company's LinkedIn URL in, its full firmographic record out./enrichment /company company_find_by_domainPOST/v2Domain to LinkedIn API A web domain in, the company's LinkedIn URL out./enrichment /domain-to-linkedin company_get_domainPOST/v2LinkedIn URL to Domain A company's LinkedIn URL in, its web domain out./enrichment /linkedin-to-domain company_tam_by_jobsPOST/v2TAM by Jobs API Job filters in, the companies hiring for them out, with their matching job counts./company /tam-by-jobs company_tam_by_peoplePOST/v2TAM by People API People filters in, the companies whose employees match out, with a count for each./company /tam-by-people company_employees_by_countryPOST/v2Headcount by country A company in, its headcount split by country out./enrichment /company-distribution-by-country company_employees_by_departmentPOST/v2Headcount by department A company in, its headcount split by department out./enrichment /company-distribution-by-department
JSON · data/pages/mcp.json › tools (first two groups)
{
"title": "One tool **per endpoint**",
"subtitle": "Tools are named after what they return, and each API tool runs exactly one endpoint: what the API reference says about a parameter or a response applies unchanged.",
"groups": [
{
"label": "People",
"items": [
{
"tool": "people_search",
"product": "/products/people-search",
"job": "Title, level, function and company filters in, matching people across companies out."
},
{
"tool": "people_employee_finder",
"product": "/products/employee-finder",
"job": "A company in, its current employees by level, function and country out."
},
{
"tool": "people_waterfall_icp",
"product": "/products/waterfall-icp",
"job": "A company and ranked title tiers in, the best-placed people out, tier by tier."
},
{
"tool": "people_enrich",
"product": "/products/profile-enrichment",
"job": "A profile URL in, the person and their whole career out."
},
{
"tool": "people_find_work_email",
"product": "/products/email-enrichment",
"job": "A profile URL in, the verified work email out, or Not Found instead of a guess."
},
{
"tool": "people_find_phone",
"product": "/products/phone-enrichment",
"job": "A profile URL in, mobile and direct US phone numbers out."
},
{
"tool": "people_lookup_by_email",
"product": "/products/reverse-email-lookup",
"job": "An email address in, the professional profile behind it out."
},
{
"tool": "people_lookup_by_phone",
"product": "/products/reverse-phone-lookup",
"job": "A phone number in, the professional profile behind it out."
}
]
},
{
"label": "Companies",
"items": [
{
"tool": "company_search",
"product": "/products/company-search",
"job": "Industry, size, location and funding filters in, matching companies out."
},
{
"tool": "company_enrich",
"product": "/products/company-enrichment",
"job": "A company's LinkedIn URL in, its full firmographic record out."
},
{
"tool": "company_find_by_domain",
"product": "/products/domain-to-linkedin",
"job": "A web domain in, the company's LinkedIn URL out."
},
{
"tool": "company_get_domain",
"name": "LinkedIn URL to Domain",
"endpoint": "POST /v2/enrichment/linkedin-to-domain",
"href": "https://docs.blitz-api.ai/api-reference/company-enrichment/linkedin-url-to-domain",
"job": "A company's LinkedIn URL in, its web domain out."
},
{
"tool": "company_tam_by_jobs",
"product": "/products/tam-by-jobs",
"job": "Job filters in, the companies hiring for them out, with their matching job counts."
},
{
"tool": "company_tam_by_people",
"product": "/products/tam-by-people",
"job": "People filters in, the companies whose employees match out, with a count for each."
},
{
"tool": "company_employees_by_country",
"name": "Headcount by country",
"endpoint": "POST /v2/enrichment/company-distribution-by-country",
"href": "https://docs.blitz-api.ai/api-reference/utilities/company-employment-distribution",
"job": "A company in, its headcount split by country out."
},
{
"tool": "company_employees_by_department",
"name": "Headcount by department",
"endpoint": "POST /v2/enrichment/company-distribution-by-department",
"href": "https://docs.blitz-api.ai/api-reference/utilities/company-department-distribution",
"job": "A company in, its headcount split by department out."
}
]
}
],
"note": {
"title": "Records",
"text": "Tool calls run on your BlitzAPI plan and count exactly like API calls.",
"href": "/pricing",
"label": "See plans"
}
}McpPrompts
components/mcp/McpPrompts.astrokind: prompts (root field of data/pages/mcp.json)Prompts to paste once a tool is connected: index, title, the prompt in a light field, the copy button. Every prompt stays selectable text without JavaScript.
Notinventing prompts: they come from the docs page, so what they promise is documented.
Five prompts to try
Paste one into your AI tool once the server is connected. The last one runs a large job the right way: as a script, not as one giant tool call.
Find a decision maker
Using BlitzAPI, find the Head of Sales at stripe.com and get their work email.
Build a prospect list
Find 25 VPs of Marketing at B2B SaaS companies in the US with 50 to 200 employees. Show name, title, company and profile URL in a table.
Check your account
How many records do I have left on my BlitzAPI plan, and what's my rate limit per endpoint?
Ask the docs
What parameters does the waterfall ICP keyword search accept? Show me a complete example JSON body.
Write the pipeline
Write a Python script that takes a list of company domains, converts each to a LinkedIn URL, then finds the VP of Sales using BlitzAPI waterfall search. Save the results to a CSV and include retry logic.
JSON · data/pages/mcp.json › prompts
{
"title": "Five prompts **to try**",
"subtitle": "Paste one into your AI tool once the server is connected. The last one runs a large job the right way: as a script, not as one giant tool call.",
"source": "https://docs.blitz-api.ai/guide/integrations/MCP",
"items": [
{
"title": "Find a decision maker",
"prompt": "Using BlitzAPI, find the Head of Sales at stripe.com and get their work email."
},
{
"title": "Build a prospect list",
"prompt": "Find 25 VPs of Marketing at B2B SaaS companies in the US with 50 to 200 employees. Show name, title, company and profile URL in a table."
},
{
"title": "Check your account",
"prompt": "How many records do I have left on my BlitzAPI plan, and what's my rate limit per endpoint?"
},
{
"title": "Ask the docs",
"prompt": "What parameters does the waterfall ICP keyword search accept? Show me a complete example JSON body."
},
{
"title": "Write the pipeline",
"prompt": "Write a Python script that takes a list of company domains, converts each to a LinkedIn URL, then finds the VP of Sales using BlitzAPI waterfall search. Save the results to a CSV and include retry logic."
}
]
}DarkWorkflowGrid
components/sections/DarkWorkflowGrid.astrokind: featuresThe dark matrix « Built for every data workflow »: six workflows, one acquisition CTA, on ink.
Built for every data workflow
Everything required to discover companies, identify buyers, enrich records, detect signals, and activate data from a single infrastructure layer.
JSON · data/pages/about.json › features[1]
{
"kind": "features",
"title": "Built for every **data workflow**",
"subtitle": "Everything required to discover companies, identify buyers, enrich records, detect signals, and activate data from a single infrastructure layer.",
"items": [
{
"title": "Build TAM",
"text": "Create dynamic markets using companies, people, jobs and signals"
},
{
"title": "Find Decision Makers",
"text": "Identify decision makers and key stakeholders across every account."
},
{
"title": "Jobs Intelligence",
"text": "Turn millions of job postings into signals and market intelligence."
},
{
"title": "Enrich Records",
"text": "Transform incomplete records into complete, actionable profiles."
},
{
"title": "Identity Resolution",
"text": "Resolve domains, emails, LinkedIn URLs, and matching keys across fragmented datasets."
},
{
"title": "AI-Native Infrastructure",
"text": "Plug agents and AI workflows into the data layer through the MCP server, Skills and typed SDKs."
}
]
}The blocks that carry a voice
Pains, the use-case matrix, the endpoint toolkit and chain, the founder quote, the stack quote, the counters. They read a persona JSON or about.json, and the template derives their props structurally.
PainsSection
components/persona/PainsSection.astrokind: split + features (untitled)The pains row: an editorial column, the persona scene, three cells. The template derives everything from the first split and the untitled features.
Notleaving its bottom padding above a bordered band: it reads as an empty ruled strip, rail to rail. That is what closesOnBand removes.
Replace manual
GTM research
JSON · content/teams/gtm-engineers.json › pains split + untitled features
{
"kind": "split",
"title": "Replace manual **GTM research**",
"subtitle": "Search, enrich, validate, and route B2B data at scale",
"items": [
{
"text": "BlitzAPI gives you clean endpoints to build the workflow once, run it at scale, and push structured outputs into the tools your team already uses."
},
{
"text": "Create repeatable workflows for outbound, CRM enrichment, and routing."
},
{
"text": "Send clean company, contact, email, and signal data into your stack."
},
{
"title": "Talk to the team",
"href": "/contact"
}
]
}
{
"kind": "features",
"items": [
{
"title": "Less manual work",
"text": "Replace research, lookup, and enrichment tasks with API calls."
},
{
"title": "Cleaner GTM data",
"text": "Structured outputs, ready for your CRM, outbound tools, and workflows."
},
{
"title": "Ready to scale",
"text": "Run the same playbook across hundreds or thousands of accounts."
}
]
}WorkplaceSection
components/persona/WorkplaceSection.astrokind: split (founder) + split (Plug BlitzAPI)The human proof of a persona page: the founder quote, the two dataset volumes, and how a GTM uses it in their stack. A four-cell matrix with mono headers: the quote spans two columns with the two volumes on its right, and the stack quote runs full width below.
Notputting a pipeline diagram back in it. EndpointChain, right above it on the team pages, already draws this role's calls; the generic PERSON, EMAIL, PHONE cell it used to carry contradicted that chain on all five pages.
A data layer for GTM systems that need to move fast
Founder
“BlitzAPI helps GTM teams replace manual research with programmable data workflows. Search accounts, identify decision makers, enrich records, validate emails, and send clean data into your systems.”
Data layer · Continuous
Data volume · Aggregate
Plug BlitzAPI into your stack
“Use BlitzAPI as the API layer behind your Clay workflows, CRMs, internal tools, automations, and custom agents. High-volume playbooks, without per-record anxiety.”
JSON · content/teams/gtm-engineers.json › founder split + « Plug BlitzAPI » split
{
"kind": "split",
"title": "A data layer for GTM systems that need to **move fast**",
"items": [
{
"title": "Antoine Blitz, Founder at BlitzAPI",
"text": "BlitzAPI helps GTM teams replace manual research with programmable data workflows. Search accounts, identify decision makers, enrich records, validate emails, and send clean data into your systems."
}
]
}
{
"kind": "split",
"title": "Plug BlitzAPI into your stack",
"items": [
{
"text": "Use BlitzAPI as the API layer behind your Clay workflows, CRMs, internal tools, automations, and custom agents. High-volume playbooks, without per-record anxiety."
}
]
}CountersBand
components/persona/CountersBand.astroThe odometer counters. Only authorized KPIs, and a note that defines what a record is.
A record is any object the infrastructure operates on: companies, people, job postings and signals. One organisation can account for many.
JSON · data/pages/about.json › stats
[
{
"value": "1B+",
"label": "Records in our data infrastructure",
"note": "A record is any object the infrastructure operates on: companies, people, job postings and signals. One organisation can account for many."
}
]UseCaseMatrix
components/persona/UseCaseMatrix.astrokind: usecasesWhat a role builds with BlitzAPI: the destination matrix of the site on the gray band of the teams pages (light cells, strong rules). A stretched link: the title is the link, its ::after covers the cell, so the whole cell stays clickable while the type and the description are read in order outside the link. Arrow visible at rest on every breakpoint, focus ring drawn inside the cell. The title link carries a scroll-margin-top as tall as the row above it, so Shift+Tab brings the whole cell, ring and type included, clear of the sticky nav.
Notan aria-label on a cell that wraps its whole content: it replaces the content for screen readers, who then never hear the description. Also persona/PlaybooksGrid, the October version that points to the Learn routes, and usecase/PlaybookGrid, which sits on the page background and hides its arrow on touch screens.
What Software Developers build with BlitzAPI
Features and pipelines backed by the same REST endpoints.
- Capability
Data products
Add company, contact, job, and signal data inside SaaS products or internal tools.
- Use case
Enrichment APIs
Complete company and contact records with emails, phones, websites, and profile data.
- Product
Search features
Build company, people, and job search experiences with API-based filters and outputs.
- Product
Validation layers
Validate emails, catch-all domains included, and store only addresses that were proven, never guessed.
- Product
Signal pipelines
Use job postings, hiring trends, and company signals to trigger product or GTM actions.
- Docs
AI agents
Give agents reliable B2B data for research, enrichment, scoring, and workflow execution.
JSON · content/teams/developers.json › usecases (one cell without href)
{
"kind": "usecases",
"title": "What Software Developers **build** with BlitzAPI",
"subtitle": "Features and pipelines backed by the same REST endpoints.",
"items": [
{
"title": "Data products",
"text": "Add company, contact, job, and signal data inside SaaS products or internal tools."
},
{
"title": "Enrichment APIs",
"text": "Complete company and contact records with emails, phones, websites, and profile data.",
"href": "/use-cases/profile-enrichment"
},
{
"title": "Search features",
"text": "Build company, people, and job search experiences with API-based filters and outputs.",
"href": "/products/company-search"
},
{
"title": "Validation layers",
"text": "Validate emails, catch-all domains included, and store only addresses that were proven, never guessed.",
"href": "/products/email-enrichment"
},
{
"title": "Signal pipelines",
"text": "Use job postings, hiring trends, and company signals to trigger product or GTM actions.",
"href": "/products/jobs-signal"
},
{
"title": "AI agents",
"text": "Give agents reliable B2B data for research, enrichment, scoring, and workflow execution.",
"href": "https://docs.blitz-api.ai/"
}
]
}EndpointToolkit
components/sections/EndpointToolkit.astrokind: toolkit (root field of a team JSON)The means at hand, as an API reference sheet: grouped by family in the mega menu order, one row per endpoint with the method and path in mono, the name, what the call takes and returns, and the plans that open it when not every plan does. The whole row links to the product page through a stretched link: the API name is the link and its ::after covers the row, so the link is named by the API alone and the path, plans and job are read in order outside it. The job line is balanced (no one-word last line), and the name link carries a scroll-margin-top so Shift+Tab brings the whole row clear of the sticky nav.
Notretyping a product name or an endpoint in the page JSON, or writing a plan by hand: plans are computed from COMPARE_GROUPS in config/pricing.ts.
The calls behind each client playbook
Build the playbook once on these endpoints, then run it per client with that client's filters. One API key, structured JSON in and out.
- Endpoints
- 05
- Data families
- 03
Search & Discovery
- POST
/v2Company Search API Send one client's ICP filters, get the matching companies back, each with its LinkedIn URL./search /companies - POST
/v2People Search API Send a client's persona filters, get matching people across that client's market, each with their full position history./search /people - POST
/v2Waterfall ICP API Send an account and the client's title hierarchy, get the strongest available contact back./search /waterfall-icp-keyword
Enrichment
- POST
/v2Email Enrichment API Send a contact's LinkedIn URL, get a verified work email back, or Not Found./enrichment /email
Jobs Intelligence
- POST
/v2Jobs Signal API Send a target account's LinkedIn URL, get its live job postings back, filtered by title, location or posting date./jobs /company
Client work
Running BlitzAPI inside client engagements you operate is a standard, supported use on any plan. Reselling the data needs the reseller agreement of Build Your Infra; embedding it in your own product is Blitz Embedded.
Book a call about reseller termsJSON · content/teams/agencies.json › toolkit (with its note)
{
"title": "The calls behind **each client playbook**",
"subtitle": "Build the playbook once on these endpoints, then run it per client with that client's filters. One API key, structured JSON in and out.",
"items": [
{
"product": "/products/company-search",
"job": "Send one client's ICP filters, get the matching companies back, each with its LinkedIn URL."
},
{
"product": "/products/people-search",
"job": "Send a client's persona filters, get matching people across that client's market, each with their full position history."
},
{
"product": "/products/waterfall-icp",
"job": "Send an account and the client's title hierarchy, get the strongest available contact back."
},
{
"product": "/products/email-enrichment",
"job": "Send a contact's LinkedIn URL, get a verified work email back, or Not Found."
},
{
"product": "/products/jobs-signal",
"job": "Send a target account's LinkedIn URL, get its live job postings back, filtered by title, location or posting date."
}
],
"note": {
"title": "Client work",
"text": "Running BlitzAPI inside client engagements you operate is a standard, supported use on any plan. Reselling the data needs the reseller agreement of Build Your Infra; embedding it in your own product is Blitz Embedded.",
"href": "https://cal.com/antoine-blitz-acepmu/discovery-call-build-your-infra-blitz-api",
"label": "Book a call about reseller terms"
}
}EndpointChain
components/sections/EndpointChain.astrokind: workflow (root field of a team JSON)How the calls chain: a dark panel on the gutter, a rail of numbered nodes joined by a dashed connector, one row per call (call, what it does, what it passes on). The connector runs three times when its step enters the viewport, under 5 seconds, then stays still; it never moves under reduced motion. Under 1100px the call stacks over its text and the output stays on the right; under 768px everything stacks. The « Passes on » column lines up by itself; the last output, in accent, is what the chain delivers. The API names are the only links, underlined at rest; the path is white, because blue on ink reads as a link on this site.
Nota step whose output the next one does not consume, and more than four steps: past four, the chain stops illustrating and competes with the text. The four horizontal cards of the first draft were dropped at capture (names and paths broken at 220px). Also an endless loop on the connector: movement that lasts more than 5 seconds must be stoppable by everyone (WCAG 2.2.2), not only under reduced motion.
Workflow · four calls in sequence
From an ICP to verified contacts
One way to chain them from Clay, n8n or your own code: a market goes in, verified contacts at accounts that are hiring come out.
Describe the market once: industry, size, location, keywords. Each company comes back with its LinkedIn URL.
Passes on Target companies
Pull each company's jobs, grouped by month, and keep the accounts hiring for the team you sell to.
Passes on Accounts that are hiring
Run your title cascade on each account. The engine moves down a tier only when the one above comes back empty.
Passes on Decision makers per account
Look up each decision maker's work email and keep the ones who come back with a verified address. The rest return Not Found.
Delivers Verified contacts, ready to sequence
JSON · content/teams/gtm-engineers.json › workflow
{
"title": "From an ICP to **verified contacts**",
"subtitle": "One way to chain them from Clay, n8n or your own code: a market goes in, verified contacts at accounts that are hiring come out.",
"steps": [
{
"product": "/products/company-search",
"text": "Describe the market once: industry, size, location, keywords. Each company comes back with its LinkedIn URL.",
"output": "Target companies"
},
{
"product": "/products/jobs-signal",
"text": "Pull each company's jobs, grouped by month, and keep the accounts hiring for the team you sell to.",
"output": "Accounts that are hiring"
},
{
"product": "/products/waterfall-icp",
"text": "Run your title cascade on each account. The engine moves down a tier only when the one above comes back empty.",
"output": "Decision makers per account"
},
{
"product": "/products/email-enrichment",
"text": "Look up each decision maker's work email and keep the ones who come back with a verified address. The rest return Not Found.",
"output": "Verified contacts, ready to sequence"
}
]
}EndpointCall
components/sections/EndpointCall.astroThe chip of one API call: the method, then the path in mono, split with a <wbr> before each « / ». A segment stays whole while it fits the line; wider than the line (text at 200% on a phone), it breaks at its hyphen rather than overflow its frame. Under 767px the chip and the path flow inline, so a long path moves under the method instead of being squeezed beside it.
Nota new method badge written by hand in a component: three drifted in one pass, with three paddings, two line heights and two letter spacings.
TONE LIGHT · SIZE MD · EndpointToolkit
POST/v2/search/waterfall-icp-keyword TONE DARK · SIZE MD · EndpointChain
POST/v2/search/waterfall-icp-keyword TONE LIGHT · SIZE SM · LINKED PATH
POST/v2/enrichment/person Astro · the two callers, and the small linked size
<EndpointCall method={row.method} path={row.path} tone="light" /> {/* EndpointToolkit */}
<EndpointCall method={card.method} path={card.path} tone="dark" /> {/* EndpointChain */}
<EndpointCall method="POST" path="/v2/enrichment/person" href="/products/profile-enrichment" tone="light" size="sm" /> {/* inside a mono meta line */}FAQ, proof, then the decision
Every directory page closes the same way: signed band, FAQ with structured data, the offer strip, the CTA. The order is part of the contract. **The eight benchmark pages are the one exception**: no FAQPage markup is allowed under /benchmarks since Google dropped it from results on 2026-05-07, and an offer strip beside a measurement would read as an ad. They close on the CTA alone.
FaqSection
components/sections/FaqSection.astroThe FAQ as native <details>, zero JavaScript, with its structured data. The answers are indexed and read by agents (llms-full.txt).
Notrecommending a product by name in prose without checking it still exists: FAQ residues are invisible to the link checker.
Frequently asked questions
What is a company search API?
An API that returns the companies matching your criteria, such as industry, employee range, headquarters location or keywords, as structured records you can page through. It answers which companies fit a market. To look up one company you already know, from its domain or LinkedIn URL, use Company Enrichment.
Can I use the company search API as a company lookup API?
Yes, when the lookup is by criteria: describe the companies you want, by industry, employee range, headquarters country or keywords in the profile, and get every match back with its LinkedIn URL, domain and headquarters. To look up one company you already know by its website, resolve the domain with Domain to LinkedIn, then pass the URL to Company Enrichment for the full profile.
Which filters can I combine?
Industry, company size, location, keywords, revenue, web traffic, ad activity, SIC and NAICS codes, and market signals, all combinable in a single query.
How many companies can I search?
Queries run against a data layer of 65M+ companies, so you can map entire markets instead of sampling from static databases.
What do I do with the results?
Chain company results into People Search, enrichment, validation, or CRM sync to go from a defined market to activated accounts in one workflow.
How can I test it on my ICP?
Sign up on app.blitz-api.ai with 1,000 free records and run your real targeting filters before you commit.
How do I page through a large company search?
Company search is cursor-paginated: pass the cursor from each response into the next request, and a null cursor in the response means you have reached the end. The Python and TypeScript SDKs iterate the pages for you.
JSON · content/products/company-search.json › faq
[
{
"q": "What is a company search API?",
"a": "An API that returns the companies matching your criteria, such as industry, employee range, headquarters location or keywords, as structured records you can page through. It answers which companies fit a market. To look up one company you already know, from its domain or LinkedIn URL, use Company Enrichment."
},
{
"q": "Can I use the company search API as a company lookup API?",
"a": "Yes, when the lookup is by criteria: describe the companies you want, by industry, employee range, headquarters country or keywords in the profile, and get every match back with its LinkedIn URL, domain and headquarters. To look up one company you already know by its website, resolve the domain with Domain to LinkedIn, then pass the URL to Company Enrichment for the full profile.",
"link": {
"label": "See the company enrichment API",
"href": "/products/company-enrichment"
}
},
{
"q": "Which filters can I combine?",
"a": "Industry, company size, location, keywords, revenue, web traffic, ad activity, SIC and NAICS codes, and market signals, all combinable in a single query."
},
{
"q": "How many companies can I search?",
"a": "Queries run against a data layer of 65M+ companies, so you can map entire markets instead of sampling from static databases."
},
{
"q": "What do I do with the results?",
"a": "Chain company results into People Search, enrichment, validation, or CRM sync to go from a defined market to activated accounts in one workflow."
},
{
"q": "How can I test it on my ICP?",
"a": "Sign up on app.blitz-api.ai with 1,000 free records and run your real targeting filters before you commit."
},
{
"q": "How do I page through a large company search?",
"a": "Company search is cursor-paginated: pass the cursor from each response into the next request, and a null cursor in the response means you have reached the end. The Python and TypeScript SDKs iterate the pages for you."
}
]Testimonials
components/sections/Testimonials.astroThe testimonial carousel. Hidden in every production build while QUOTES_ARE_PLACEHOLDERS is true in config/testimonials.ts (the four quotes are placeholders until the real verbatims arrive); it renders on the dev server.
Not rendered in this build: QUOTES_ARE_PLACEHOLDERS is true in config/testimonials.ts. Flip it once the real verbatims are in, and the carousel appears here and on the home page.
Astro
<Testimonials /> {/* slides: config/testimonials.ts */}CtaSection
components/sections/CtaSection.astroThe pre-footer CTA. Same words everywhere, so the site ends every chapter on the same decision.
Astro
<CtaSection cta={ctaId('product', 'cta_section', 'primary')} />One claim, one drawing, one twin table
The benchmark figures follow their own grammar, because they publish measurements rather than copy: every figure carries its population and its source and keeps a readable table of the same numbers, and it states a CLAIM computed from the data unless the claim is dropped by explicit decision (claim={false}, the directory figure on /benchmarks). Color is never the only encoding, no red, and rank one is marked by weight alone. They read the `benchmarks` collection, which is generated: no number is ever written by hand.
ChartFrame
components/benchmark/ChartFrame.astroThe common frame of every measurement figure: one claim in large type, the drawing, a source line, and the exact numbers either folded or open. It THROWS at build when claim, n or source is missing: a forgotten claim never turns into a silent untitled figure, and a figure without its population proves nothing. Dropping the claim is explicit, claim={false}, and leaves no element, margin or rule in its place.
Notwriting the claim by hand. Five universal claims have been published false in this module, each contradicted by the figure right below it. A claim is walked over the data before it is written, and when it only holds on one measure of a switchable figure, it NAMES that measure.
On accurate records per 100, the providers range from 31.9 to 82.4 on the same list.
5 measures, the same 6 providers ranked on each one, strongest at the top
Coverage
Does it return a person at all?
- 1Apollo96.8%
- 2Prospeo94.9%
- 3BlitzAPI90.4%
- 4MoltSets84.6%
- 5GetLeads.io81.1%
- 6QuickEnrich68.8%
Accurate per 100
Out of 100 you send, how many come back usable?
- 1BlitzAPI82.4
- 2Apollo70.0
- 3Prospeo52.7
- 4QuickEnrich43.8
- too close to separate5MoltSets43.7
- 6GetLeads.io31.9
Accuracy
When it answers, is the answer right?
- 1BlitzAPI91.2%
- 2Apollo72.3%
- 3QuickEnrich63.7%
- 4Prospeo55.5%
- 5MoltSets51.7%
- 6GetLeads.io39.3%
Right employer
Right company, whatever the title says?
separation not tested
- 1BlitzAPI93.7%
- 2Apollo87.6%
- 3QuickEnrich75.4%
- 4GetLeads.io67.7%
- 5Prospeo66.9%
- 6MoltSets65.8%
Stale rate
How often does it name a job the person left?
separation not tested
- 1BlitzAPI4.4%
- 2Apollo10.8%
- 3Prospeo17.5%
- 4QuickEnrich24.6%
- 5GetLeads.io32.2%
- 6MoltSets33.2%
Astro · the frame throws when claim, n or source is missing
<ChartFrame claim={computed} n={d.targets} source={`test ${d.testId}`} readAs="..." />DimensionRanks
components/benchmark/DimensionRanks.astroColumns are measures, rows are ranks: it answers « depending on what I optimise, which one ». The column order is derived, not chosen: measures whose separation was TESTED first, then the one where the publisher places lowest, then the tightest race. The rule lives in the figure itself: « separation not tested » in a column header, « too close to separate » on a row.
Nota radar or a composite score. A radar adds units that do not add up and invents an area the measurement does not have; a composite score is the « Winner » the recipe forbids.
5 measures, the same 6 providers ranked on each one, strongest at the top
Coverage
Does it return a person at all?
- 1Apollo96.8%
- 2Prospeo94.9%
- 3BlitzAPI90.4%
- 4MoltSets84.6%
- 5GetLeads.io81.1%
- 6QuickEnrich68.8%
Accurate per 100
Out of 100 you send, how many come back usable?
- 1BlitzAPI82.4
- 2Apollo70.0
- 3Prospeo52.7
- 4QuickEnrich43.8
- too close to separate5MoltSets43.7
- 6GetLeads.io31.9
Accuracy
When it answers, is the answer right?
- 1BlitzAPI91.2%
- 2Apollo72.3%
- 3QuickEnrich63.7%
- 4Prospeo55.5%
- 5MoltSets51.7%
- 6GetLeads.io39.3%
Right employer
Right company, whatever the title says?
separation not tested
- 1BlitzAPI93.7%
- 2Apollo87.6%
- 3QuickEnrich75.4%
- 4GetLeads.io67.7%
- 5Prospeo66.9%
- 6MoltSets65.8%
Stale rate
How often does it name a job the person left?
separation not tested
- 1BlitzAPI4.4%
- 2Apollo10.8%
- 3Prospeo17.5%
- 4QuickEnrich24.6%
- 5GetLeads.io32.2%
- 6MoltSets33.2%
Collection · benchmarks/contact-data-september-2026 › providers[].kpi + interval
[
{
"key": "coverage_pct",
"label": "Coverage",
"question": "Does it return a person at all?",
"higherIsBetter": true,
"unit": "pct"
},
{
"key": "accuracy_pct",
"label": "Accuracy",
"question": "When it answers, is the answer right?",
"higherIsBetter": true,
"unit": "pct"
},
{
"key": "net_yield",
"label": "Accurate per 100",
"question": "Out of 100 you send, how many come back usable?",
"higherIsBetter": true,
"unit": "num"
},
{
"key": "correct_employer_pct",
"label": "Right employer",
"question": "Right company, whatever the title says?",
"higherIsBetter": true,
"unit": "pct"
},
{
"key": "stale_pct",
"label": "Stale rate",
"question": "How often does it name a job the person left?",
"higherIsBetter": false,
"unit": "pct"
}
]HeadToHeadRail
components/benchmark/HeadToHeadRail.astroOne row per competitor, sorted by SMALLEST gap first, and the entry point to the five duel pages. Two counterweights are rendered unconditionally: the coverage the publisher gives up, and the contacts where the competitor is right and the publisher is not (not « wrong »: that count also holds the publisher’s unverifiable answers, which the methodology calls neither right nor wrong). That sentence is counterLine() of viz.ts, shared with the duel page: written twice, it drifted once.
Notreusing the accuracy of the scorecard. A duel is scored on the contacts BOTH returned; the two bases differ by a point or more, and mixing them publishes a false page nothing in the build would catch.
On the 3,081 contacts both returned
18.1 points apart, right employer and title.
Apollo answers more often: it returned a person for 96.8% of the full list against 90.4%.
Apollo was right where BlitzAPI was not on 108 of those 3,081 contacts.
Kept together, BlitzAPI first and Apollo on the misses: 86.9 accurate per 100 instead of 82.4, for 330 extra queries.
On the 2,287 contacts both returned
28.7 points apart, right employer and title.
Reach goes the other way here: BlitzAPI returned a person for 90.4% of the full list against 68.8%.
QuickEnrich was right where BlitzAPI was not on 18 of those 2,287 contacts.
Kept together, BlitzAPI first and QuickEnrich on the misses: 83.3 accurate per 100 instead of 82.4, for 330 extra queries.
On the 3,033 contacts both returned
33.4 points apart, right employer and title.
Prospeo answers more often: it returned a person for 94.9% of the full list against 90.4%.
Prospeo was right where BlitzAPI was not on 21 of those 3,033 contacts.
Kept together, BlitzAPI first and Prospeo on the misses: 84.2 accurate per 100 instead of 82.4, for 330 extra queries.
On the 2,730 contacts both returned
39.8 points apart, right employer and title.
Reach goes the other way here: BlitzAPI returned a person for 90.4% of the full list against 84.6%.
MoltSets was right where BlitzAPI was not on 34 of those 2,730 contacts.
Kept together, BlitzAPI first and MoltSets on the misses: 84.8 accurate per 100 instead of 82.4, for 330 extra queries.
On the 2,683 contacts both returned
52.4 points apart, right employer and title.
Reach goes the other way here: BlitzAPI returned a person for 90.4% of the full list against 81.1%.
GetLeads.io was right where BlitzAPI was not on 10 of those 2,683 contacts.
Kept together, BlitzAPI first and GetLeads.io on the misses: 83.4 accurate per 100 instead of 82.4, for 330 extra queries.
Collection · duels filtered on the publisher, + pairBest
{
"a": "blitzapi",
"b": "apollo",
"shared": 3081,
"both_accurate": 2150,
"only_a": 666,
"only_b": 108,
"neither": 157,
"a_accuracy_pct": 91.4,
"b_accuracy_pct": 73.3,
"gap": 18.1,
"ahead": "blitzapi"
}DuelScoreboard
components/benchmark/DuelScoreboard.astroTwo columns of equal width, always both rendered, so an empty one is SEEN empty. Three separation states: tested, too close to separate, not tested. An exact tie belongs to neither column. It opened the head to head pages until 2026-09-22, when DuelFaceOff replaced it: it said WHO was ahead, not by how much nor where on the scale. It is kept here as a specimen, like DuelLedger. The only part that stays a reference for a future two-sided figure is the pair of equal columns, both always rendered. Its counting is NOT: it predates separation() (viz.ts), puts a measure with no published interval in the better side’s column and in its « N of M », and its empty-column sentence counts those measures among the ones « this run separates ». That is why this specimen and DuelFaceOff, two cards below, count the same pair differently.
Nothiding the competitor column when it is empty: on a page published by one of the two providers measured, the empty column is the proof, not an embarrassment. And copying its counting: a future two-sided figure takes its leader and its denominator from separation(), like DuelFaceOff, so only separated rows are marked and M counts the rows that carry an interval.
BlitzAPI is ahead on5 of 6
- accuracy91.2% against 72.3%18.9 points, against a combined interval of 2.5
- net yield82.4 against 70.012.4 points, against a combined interval of 2.8
- correct employer93.7% against 87.6%6.1 points, separation not tested
- stale4.4% against 10.8%6.4 points, separation not tested
- history recall96.1% against 86.1%10.0 points, separation not tested
Apollo is ahead on1 of 6
- coverage96.8% against 90.4%6.4 points, against a combined interval of 1.6
Collection · the two providers of one pair, six measures, three separation states · retired counting (untested measures counted as ahead): do not copy it, see separation()
{ key: 'coverage_pct', us: 90.4, them: 96.8, usMargin: 1, themMargin: 0.6 }DuelFaceOff
components/benchmark/DuelFaceOff.astroTwo providers face to face on the main measures: one row per measure, mirrored bars growing out of a center column of labels, the same scale on every row and on both sides, the two values always written: every row shares one inset and one value column, the featured row included, so the outer end of every track is the same 100. The header prints « Ahead on N of M tested » on BOTH sides, M being the measures that carry a published interval (the only rows where a side can be marked), so a side at zero is seen at zero; when a name no longer fits its half, that side moves to its own line instead of overflowing. A side is marked ahead (weight AND the word « Ahead », never color alone) only where the gap is wider than both confidence intervals added together; without an interval the row prints the gap and « separation not tested »; a gap inside the intervals is « too close to separate »; an exact tie on the printed values belongs to neither side. Lower-is-better rows say so, and the marker follows the direction while the bar keeps encoding the value. One row can be featured: larger, in a panel, with one sentence saying what it combines. On the duel pages it is accurate records per 100 contacts, the measure the report ranks on, with its two factors (coverage, accuracy) right below it.
Notturning the featured row into a composite score. It must be a published measure the reader can recompute from the rows below it. And do not sort the rows by where the publisher leads: coverage, where the competitor leads against Apollo and Prospeo, stays the second row on every pair page.
BlitzAPIAhead on 2 of 3 tested
ApolloAhead on 1 of 3 tested
The measure the report ranks on
Accurate records per 100 contacts
per 100 queried · higher is better
BlitzAPI ahead by 12.4 pointsbeyond the combined interval of 2.8
BlitzAPI: 82.4Ahead
Apollo: 70.0
Coverage multiplied by accuracy: out of every 100 contacts sent, how many came back with the right current employer and a matching title.
Coverage
a person returned at all
% of queried · higher is better
Apollo ahead by 6.4 pointsbeyond the combined interval of 1.6
BlitzAPI: 90.4%
Apollo: 96.8%Ahead
Accuracy
right current employer and a matching title
% of answered · higher is better
BlitzAPI ahead by 18.9 pointsbeyond the combined interval of 2.5
BlitzAPI: 91.2%Ahead
Apollo: 72.3%
Wrong title
right employer, the title does not match
% of answered · lower is better
BlitzAPI lower by 12.7 pointsseparation not tested
BlitzAPI: 2.5%
Apollo: 15.2%
Stale employer rate
an employer the person has left
% of answered · lower is better
BlitzAPI lower by 6.4 pointsseparation not tested
BlitzAPI: 4.4%
Apollo: 10.8%
Second specimen, same edition: MoltSets and QuickEnrich, the first pair of the run where a measure with an interval (accurate records per 100) sits inside the combined interval, to show the « too close to separate » state. No pair with BlitzAPI shows that state in this run. No pair of this run is level on a printed value, so the « Level » state has no real specimen.
MoltSetsAhead on 1 of 3 tested
QuickEnrichAhead on 1 of 3 tested
The measure the report ranks on
Accurate records per 100 contacts
per 100 queried · higher is better
Too close to separate0.1 points apart, inside the combined interval of 3.4
MoltSets: 43.7
QuickEnrich: 43.8
Coverage multiplied by accuracy: out of every 100 contacts sent, how many came back with the right current employer and a matching title.
Coverage
a person returned at all
% of queried · higher is better
MoltSets ahead by 15.8 pointsbeyond the combined interval of 2.7
MoltSets: 84.6%Ahead
QuickEnrich: 68.8%
Accuracy
right current employer and a matching title
% of answered · higher is better
QuickEnrich ahead by 12.0 pointsbeyond the combined interval of 3.7
MoltSets: 51.7%
QuickEnrich: 63.7%Ahead
Wrong title
right employer, the title does not match
% of answered · lower is better
QuickEnrich lower by 2.5 pointsseparation not tested
MoltSets: 14.1%
QuickEnrich: 11.6%
Stale employer rate
an employer the person has left
% of answered · lower is better
QuickEnrich lower by 8.6 pointsseparation not tested
MoltSets: 33.2%
QuickEnrich: 24.6%
Collection · the pair's five main measures, built by duel/model.ts (faceOffMeasures), the same call as the live page
{
"key": "coverage_pct",
"label": "Coverage",
"name": "coverage",
"note": "a person returned at all",
"base": "% of queried",
"higherIsBetter": true,
"unit": "pct",
"us": 90.4,
"them": 96.8,
"usMargin": 1,
"themMargin": 0.6
}DuelLedger
components/benchmark/DuelLedger.astroEvery published segment, on four measures, walked in both directions. It was the transparency device of a duel page until session 46, when the section was removed for length: the WALK survives in the page, and its result is published as one generated sentence under the face-off figure of each duel page (FaceOffSection), right after the coverage rank sentence. The component is kept, and specimened here, because the sentence and it read the same walk, and because a longer form may be wanted again.
Notcopying the row tie flag. It is one boolean per row, computed on accurate records per 100 between the FIRST and the SECOND of that row: on a pair where the competitor sits fifth, it would mark « too close » a gap of several dozen points.
This is the EMPTY STATE, rendered on purpose: on two of the five published pairs the competitor is ahead on no row at all. Hiding the block would turn those two pages into a pitch, and take the other three down with them.
Collection · segments walked in both directions; the empty state is a written sentence
emptyState: 'The N published segments, each read on coverage, accuracy, accurate records per 100 and the stale rate, make N x 4 segment-and-measure comparisons. X is ahead of or level with BlitzAPI on none of them.'EditionIndex
components/benchmark/EditionIndex.astroThe list of every published report, built to absorb one a month. It is ALWAYS rendered, even with a single edition: a shape never seen on screen has never been measured, and it would appear for the first time in production. Year grouping keys off the spread of years, not a count.
Notone data-benchmark for the whole page. At twelve editions, eleven reports would live under the test id of the twelfth, and the page would silently attribute one run’s measurements to another.
Show the 1 earlier edition
Collection · every published run. Here with visible=0, so the fold renders with real data
{
"slug": "contact-data-september-2026",
"testId": "2026-09-17_combined",
"testDate": "2026-09-17T00:00:00.000Z",
"headline": "B2B data provider benchmark, September 2026",
"targets": 3445,
"providersRanked": 6,
"spread": 50.50000000000001,
"pdfPath": "/benchmarks/contact-data-september-2026/report.pdf"
}RankTrend
components/benchmark/RankTrend.astroHow positions move from one edition to the next. It renders NOTHING below two editions of the same protocol version: a trend on one point is not a trend, and an empty state would promise instead of stating. It plots the RANK, not the value, because every edition is a different list of contacts.
Notreading it as performance over time, and shipping it unmeasured. It has never been on screen, because no page has two comparable editions yet: the layout recipe runs again in full the month the second one lands.
Not a measurement. One edition is published, so this specimen feeds the same ranks under two dates: the lines are flat by construction. It exists so the geometry, the direct labels and the axis are measured before the second edition lands, instead of appearing for the first time in production.
- August 2026
- September 2026
| Provider | August 2026 | September 2026 |
|---|---|---|
| BlitzAPI | 1 (82.4) | 1 (82.4) |
| Apollo | 2 (70.0) | 2 (70.0) |
| Prospeo | 3 (52.7) | 3 (52.7) |
| QuickEnrich | 4 (43.8) | 4 (43.8) |
| MoltSets | 5 (43.7) | 5 (43.7) |
| GetLeads.io | 6 (31.9) | 6 (31.9) |
Only providers present in every edition shown carry a line: a line drawn across an edition a provider did not take part in would not mean anything. Each edition is a different list of contacts, so a position can move because the list moved.
LAYOUT SPECIMEN · the same edition twice, under two dates. Flat lines are the point: nothing here is a measurement
editions: [{ testDate: 'August 2026', ranks }, { testDate: 'September 2026', ranks }] // same ranksThe benchmark, carried to other pages
Six sections that show the measured quality of BlitzAPI data outside the report, in the grammar Antoine validated on the home: a text block with the button to the full report, and a small preview card of the figures. They share one shell (QualityShell), so the scope the recipe checks is always in the block: data-benchmark, « Measured on <date> on <n> profiles », the methodology link. Four show BlitzAPI alone and can go on any page. Two compare (the ranking, the head to head): they name competitors, so outside /benchmarks the recipe fails the page unless Antoine has listed it (the home carries the accuracy ranking since 2026-09-24). Every number is read from the benchmarks collection; the copy carries tokens only.
DataQuality
components/sections/DataQuality.astroA plain split section (redesign of 2026-09-24, Antoine: the ledger version was too big): text on the left (eyebrow, title, one paragraph, the button to the full report, the methodology link) and on the right a small preview card of the measured figures, one thin bar each, the measurement date at its foot. It proves the data quality in one glance and never takes over the page. The scope stays in the block because the recipe checks it there before it lets a quality percentage out of /benchmarks: data-benchmark on the root (the testId of a published edition that measures BlitzAPI), « Measured on <that edition’s date> on <BlitzAPI’s profile count> profiles » in its own text, a link to /benchmarks/methodology, not opened on html, body or main, not wrapping the page h1, and each quality percentage equal to the figure its label names.
Notany comparison. No competitor name, no rank, no count of providers, no average: the helper does not return them, and anywhere outside /benchmarks the recipe fails on a measured provider name and on a comparison that names no one (a rank, the other providers tested, « better than other providers », a count or an average of providers). Never type a figure in the JSON either: the copy carries tokens, the collection carries the numbers.
Data quality
Accurate B2B data, measured in public
Every month we run our own API on a list of real LinkedIn profiles and check each answer against the person's current employer and title. The full report, method included, is public.
BlitzAPI · September 2026 benchmark
- Coverage90.4%Profiles that came back with a person
- Accuracy91.2%Answers with the right employer and title
- Accurate records per 10082.4Coverage × accuracy, per 100 profiles sent
Measured on September 17, 2026 on 3,445 profiles
Data quality
Accurate B2B data, measured in public
Every month we run our own API on a list of real LinkedIn profiles and check each answer against the person's current employer and title. The full report, method included, is public.
BlitzAPI · September 2026 benchmark
- Coverage90.4%Profiles that came back with a person
- Accuracy91.2%Answers with the right employer and title
- Accurate records per 10082.4Coverage × accuracy, per 100 profiles sent
- Stale employer4.4%Answers naming an employer the person has left
Measured on September 17, 2026 on 3,445 profiles
JSON · data/quality-blocks.json › dataQuality (numbers: collection benchmarks, lib/benchmark-proof.ts)
{
"eyebrow": "Data quality",
"title": "Accurate B2B data, **measured in public**",
"subtitle": "Every month we run our own API on a list of real LinkedIn profiles and check each answer against the person's current employer and title. The full report, method included, is public.",
"cta": {
"label": "Read the full report"
},
"methodologyLabel": "How we test",
"cardLabel": "BlitzAPI · {edition} benchmark",
"measured": "Measured on {date} on {profiles} profiles",
"figures": {
"coverage": {
"label": "Coverage",
"caption": "Profiles that came back with a person"
},
"accuracy": {
"label": "Accuracy",
"caption": "Answers with the right employer and title"
},
"net_yield": {
"label": "Accurate records per 100",
"caption": "Coverage × accuracy, per 100 profiles sent"
},
"stale": {
"label": "Stale employer",
"caption": "Answers naming an employer the person has left"
}
}
}
<DataQuality copy={page.dataQuality} source="…" track={ctaId('<page>', 'inline', 'benchmark_report')} />
<DataQuality copy={…} source="…" figures={['coverage', 'accuracy', 'net_yield', 'stale']} />QualityStats
components/sections/quality/QualityStats.astroFour measured figures of BlitzAPI in one row of tiles, for a page that wants the proof in one line of reading. BlitzAPI alone: no competitor, no rank.
Nota fifth tile or a rank. The tiles are the report formula plus the stale rate, nothing more.
Data quality
Measured on real profiles, published in full
Our monthly benchmark runs BlitzAPI on a list of real LinkedIn profiles and checks each answer against the person's current employer and title.
BlitzAPI · September 2026 benchmark
- Coverage90.4%Profiles that came back with a person
- Accuracy91.2%Answers with the right employer and title
- Accurate records per 10082.4Coverage × accuracy, per 100 profiles sent
- Stale employer4.4%Answers naming an employer the person has left
Measured on September 17, 2026 on 3,445 profiles
JSON · data/quality-blocks.json › stats
{
"eyebrow": "Data quality",
"title": "Measured on real profiles, **published in full**",
"subtitle": "Our monthly benchmark runs BlitzAPI on a list of real LinkedIn profiles and checks each answer against the person's current employer and title.",
"cta": {
"label": "Read the full report"
},
"methodologyLabel": "How we test",
"cardLabel": "BlitzAPI · {edition} benchmark",
"measured": "Measured on {date} on {profiles} profiles",
"figures": {
"coverage": {
"label": "Coverage",
"caption": "Profiles that came back with a person"
},
"accuracy": {
"label": "Accuracy",
"caption": "Answers with the right employer and title"
},
"net_yield": {
"label": "Accurate records per 100",
"caption": "Coverage × accuracy, per 100 profiles sent"
},
"stale": {
"label": "Stale employer",
"caption": "Answers naming an employer the person has left"
}
}
}
<QualityStats copy={page.qualityStats} source="…" track={ctaId('<page>', 'inline', 'benchmark_report')} />QualityVerdicts
components/sections/quality/QualityVerdicts.astroWhat BlitzAPI answers are made of: one bar at 100 split into the four verdicts of the report, and its legend. Shares print as numbers out of 100 answers, without a % sign: a tight legend would otherwise let the recipe read one verdict under the next one’s label.
Nota donut or a pie: four shares of one whole read faster on one bar, and the report draws the same bar.
Data quality
What comes back when you call us
Every answer BlitzAPI returned in the benchmark was checked against the person's current profile and sorted into one of four verdicts.
BlitzAPI answers · September 2026
Out of 100 answers
- Right employer and title91.22,840 answers
- Right employer, different title2.579 answers
- Stale employer4.4138 answers
- Unverifiable1.958 answers
Measured on September 17, 2026 on 3,445 profiles
JSON · data/quality-blocks.json › verdicts
{
"eyebrow": "Data quality",
"title": "What comes back **when you call us**",
"subtitle": "Every answer BlitzAPI returned in the benchmark was checked against the person's current profile and sorted into one of four verdicts.",
"cta": {
"label": "Read the full report"
},
"methodologyLabel": "How we test",
"cardLabel": "BlitzAPI answers · {edition}",
"measured": "Measured on {date} on {profiles} profiles",
"scale": "Out of 100 answers",
"verdicts": {
"correct": "Right employer and title",
"wrong_title": "Right employer, different title",
"stale": "Stale employer",
"unverifiable": "Unverifiable"
},
"count": "{n} answers"
}
<QualityVerdicts copy={page.qualityVerdicts} source="…" />QualityHundred
components/sections/quality/QualityHundred.astro« Send 100 profiles »: a 10 by 10 grid, one cell per profile, in three states. The most concrete reading of accurate records per 100.
Notrounding each part on its own: 99 or 101 cells the month two remainders fall the same way.
Data quality
Send 100 profiles, see what comes back
Each square is one LinkedIn profile sent to our API in the benchmark: the accurate records, the answers that were not verified accurate, and the profiles that did not come back.
100 profiles sent · September 2026
- Came back accurate82
- Came back, not verified accurate8
- Did not come back10
Rounded to whole profiles.
Measured on September 17, 2026 on 3,445 profiles
JSON · data/quality-blocks.json › hundred
{
"eyebrow": "Data quality",
"title": "Send 100 profiles, **see what comes back**",
"subtitle": "Each square is one LinkedIn profile sent to our API in the benchmark: the accurate records, the answers that were not verified accurate, and the profiles that did not come back.",
"cta": {
"label": "Read the full report"
},
"methodologyLabel": "How we test",
"cardLabel": "100 profiles sent · {edition}",
"measured": "Measured on {date} on {profiles} profiles",
"legend": {
"accurate": "Came back accurate",
"returnedNotAccurate": "Came back, not verified accurate",
"notReturned": "Did not come back"
},
"rounding": "Rounded to whole profiles."
}
<QualityHundred copy={page.qualityHundred} source="…" />QualityRanking
components/sections/quality/QualityRanking.astroEvery ranked provider of the edition on one measure, as horizontal bars. Each bar carries the fixed hue of its provider and its name in full (the palette passes the dataviz validator with a color-vision reserve that requires this second encoding); the publisher carries the brand blue (Antoine, 2026-09-24) and stands out by weight too; two neighbours whose intervals do not separate them are marked « too close to separate »; the disclosure sits in the card.
Nota « winner » row or a medal. And placing it on a new page outside /benchmarks without Antoine’s decision recorded in COMPARISON_PAGES: the recipe fails the page on the first competitor name.
Benchmark
One list, every provider measured the same way
Each provider was queried on the same LinkedIn profiles and scored against a reference that belongs to none of them.
Accurate records per 100 · September 2026
- 1BlitzAPI82.4
- 2Apollo70.0
- 3Prospeo52.7
- 4QuickEnrich43.8Too close to separate
- 5MoltSets43.7
- 6GetLeads.io31.9
Measured on September 17, 2026 on 3,445 profiles
BlitzAPI runs this benchmark and is one of the providers measured.
JSON · data/quality-blocks.json › ranking (benchmarks pages only)
{
"eyebrow": "Benchmark",
"title": "One list, **every provider measured the same way**",
"subtitle": "Each provider was queried on the same LinkedIn profiles and scored against a reference that belongs to none of them.",
"cta": {
"label": "Read the full report"
},
"methodologyLabel": "How we test",
"cardLabel": "{measure} · {edition}",
"measured": "Measured on {date} on {profiles} profiles",
"disclosure": "BlitzAPI runs this benchmark and is one of the providers measured.",
"measures": {
"net_yield": "Accurate records per 100",
"coverage_pct": "Coverage",
"accuracy_pct": "Accuracy"
},
"close": "Too close to separate"
}
<QualityRanking copy={page.qualityRanking} source="…" measure="net_yield" />QualityHeadToHead
components/sections/quality/QualityHeadToHead.astroBlitzAPI against one competitor on the three measures with a published interval, two bars each. A side is « ahead » only when the gap clears both intervals added together (viz.ts › separation, on the printed values); otherwise « too close to separate », and a tie belongs to no one. Coverage is always shown, including where the competitor leads: the concession is structural.
Notdropping the coverage row on the pairs where the competitor leads on it, or marking a side ahead by color alone.
Head to head
BlitzAPI vs Apollo, on the same list
Both providers were queried on the same LinkedIn profiles and scored the same way. Where Apollo is ahead, the figure shows it.
BlitzAPI vs Apollo · September 2026
Accurate records per 100
BlitzAPI82.4Apollo70.0BlitzAPI ahead by 12.4 points
Coverage
BlitzAPI90.4%Apollo96.8%Apollo ahead by 6.4 points
Accuracy
BlitzAPI91.2%Apollo72.3%BlitzAPI ahead by 18.9 points
Measured on September 17, 2026 on 3,445 profiles
BlitzAPI runs this benchmark and is one of the providers measured.
JSON · data/quality-blocks.json › headToHead (benchmarks pages only)
{
"eyebrow": "Head to head",
"title": "BlitzAPI vs {provider}, **on the same list**",
"subtitle": "Both providers were queried on the same LinkedIn profiles and scored the same way. Where {provider} is ahead, the figure shows it.",
"cta": {
"label": "Read the head to head"
},
"methodologyLabel": "How we test",
"cardLabel": "BlitzAPI vs {provider} · {edition}",
"measured": "Measured on {date} on {profiles} profiles",
"disclosure": "BlitzAPI runs this benchmark and is one of the providers measured.",
"measures": {
"net_yield": "Accurate records per 100",
"coverage_pct": "Coverage",
"accuracy_pct": "Accuracy"
},
"ahead": "{name} ahead by {gap} points",
"close": "Too close to separate",
"level": "Level"
}
<QualityHeadToHead copy={page.qualityHeadToHead} source="…" against="apollo" />