Skip to content

Data API

Every market reading your agents take (companies, people, search terms, rankings, links, AI answers, ads) as 25 calls on one key, priced per result.

Calls
25
Noun groups
7
Shared types
9
Organization.count
You, to your agent

How many US property managers with 20 to 200 staff are there? Spend nothing.

curl -X POST "https://api.sb/leaseline.app/organizations/count?mode=try" \
  -H "Authorization: Bearer $SB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"where":{"industries":["property management"],"headcount":{"min":20,"max":200},"countries":["US"]},"maxCost":0}'
npx startup-builder do Organization.count --try --data '{"where":{"industries":["property management"],"headcount":{"min":20,"max":200},"countries":["US"]},"maxCost":0}'
{
  "name": "do",
  "arguments": {
    "mode": "try",
    "code": "return await $.Organization.count({ where: { industries: ['property management'], headcount: { min: 20, max: 200 }, countries: ['US'] }, maxCost: 0 })"
  }
}
import { $ } from 'startup-builder'

const result = await $.try.Organization.count({ where: { industries: ['property management'], headcount: { min: 20, max: 200 }, countries: ['US'] }, maxCost: 0 })
Response
{
  "count": 4180,
  "ignored": [],
  "observedAt": "2026-10-27T14:02:11Z",
  "method": "estimated"
}
Try mode reads, stores nothing and spends nothingAPI referenceIts Nouns

A Data Verb reads the market and returns a reading. A Software Verb changes your records and emits an Event.

The overview, in a founder's words: Data: every reading names when, how and what it cost.

A first pass costs about $3

Size the market, list the companies that fit with the quote that shows why, find the person at each and check their address, measure 500 search terms, read 30 results pages, ask four answer engines 20 buying questions, and diff three rivals’ links. Each line is priced from its call’s own record, so the total moves when a price does. One live run found and checked 50 heads of operations at US property managers for 29¢.

StepCallCost
How many property managers fitOrganization.countFree
100 that fit, each with the quote that shows whyOrganization.findAbout 20¢
What happened lately at each of themOrganization.enrichAbout $1.00
The person to write to at eachProspect.findAbout 5¢
100 work emails, found and checkedProspect.verifyAbout 60¢
500 search terms measuredKeyword.measureAbout 90¢
30 results pages readKeyword.searchAbout 0.9¢
20 buying questions on 4 answer enginesKeyword.askAbout 32¢
The sites linking to 3 rivals and not to youDomain.findLinksAbout 12¢
In allAbout $3.20

Each call answers one question a founder asks

One call returns one shape, so each has one price unit, one schema and one MCP tool an agent can call without reading the docs twice. The success rate is the measured share of calls that returned an answer, with its sample; a documented Workflow’s is the product of its steps’.

Verb The question it answers Unit price Works Jobs
Ad.find Which ads are my rivals paying to keep running? About 0.2¢ a search 99.9% of 309,000 A rival’s ads on Facebook and Instagram, Every ad on a phrase, A rival’s Google ads, A rival’s LinkedIn ads, TikTok ads on a phrase, How many ads, with no rows, A rival’s past search ad copy
Domain.benchmark How strong is my domain next to my rivals’? About 0.75¢ a domain 100% of 12,396 Authority, page authority and spam score, Estimated traffic and ranking terms, Referring domains and backlink totals, Monthly search ad budget
Domain.findCompetitors Who am I actually up against in search? About 5¢ per 100 rows 100% of 2,639 Who ranks for your terms, Who buys ads on your terms
Domain.findLinks Who links to my rivals and not to me? About 2¢ per 100 links 100% of 3,967 Every link, with its anchor and follow status, The sites that link, Sites linking to your rivals and not to you, Anchor text, counted, Links gained and lost by month, Is a link you earned still live
Domain.verify Do search engines know my site, and is each key page indexed? Free 99.8% of 45,746 None.
Keyword.ask Do AI answers name me, and which pages do they cite? About 0.4¢ an answer 99.96% of 131,093 An answer from ChatGPT, An answer from Gemini, An answer from Perplexity, An answer from Copilot, An answer from Claude, An answer from Google AI Mode
Keyword.find Which search terms should my pages target? About 5¢ per 100 ideas 100% of 16,219 Ideas around your seed words, How people finish your words in the search box, The questions buyers type, The terms a rival ranks for, The terms a rival pays for, What is rising on a site now
Keyword.forecast What would a month of ads on these terms cost, and how many clicks would it buy? About 9¢ a forecast 100% of 97 None.
Keyword.measure How many people search this term, what does a click cost, and how hard is page one? About 18¢ per 100 terms 99.94% of 7,106 All five measures in one row, Monthly searches and cost per click, Difficulty, for up to 1,000 terms at once, Intent, for up to 1,000 terms at once, The 12-month trend, How often the term is asked of AI tools, The same measures on Bing
Keyword.search Who shows up when my buyer searches this, and where am I? About 3¢ per 100 searches 99.1% of 1,710,120 Google results and your rank, Bing results, Local results around a place, News results, Posts on Reddit, Posts on X, Posts on Hacker News, Posts on LinkedIn, Posts on YouTube, Posts on TikTok, Posts on Stack Overflow, Issues on one GitHub repository that use the term
Monitor.check Has it changed since the last run? Free 99.6% of 2,079,088 None.
Monitor.create Can my agents tell me when something I care about changes? Free 99.2% of 2,079,088 Rank tracking, daily, AI answer watch, weekly, 3 runs on 4 engines, Buying triggers on an account, weekly, A page changes, daily, Problem posts on a site, daily, Lost links, weekly, Index state of key pages, daily
Organization.count How many companies match my customer? Free 100% of 171,792 None.
Organization.enrich What is this company, what does it run, and what happened there lately? About 20¢ per 100 companies 99.98% of 569,418 Company profile, The products a company runs, Headcount and its trend, Open roles, What happened there lately
Organization.find Which companies fit my customer, best first? About 3.8¢ per 100 rows 100% of 185,187 Companies that fit your filters, Companies that fit a sentence, Companies like ones you already have, Companies that run a product, Companies that raised this month, Companies hiring for a role, Local businesses near a place
Organization.resolve Which company is behind this visit, address or name? Free 99.97% of 419,320 The company behind a visit, The company behind an email address, The company behind a name
Page.audit Will search engines and AI crawlers read this page the way I meant? About 2¢ per 100 pages 100% of 14,847 The page as served, The page after its scripts run, Fully rendered, with Core Web Vitals
Site.audit What is wrong across my whole site, and which fix helps the most pages? About 1.5¢ per 100 pages 100% of 90 Start a crawl, Each page crawled and checked, Every URL on a site, without checks
Prospect.count How many people hold the role I sell to? Free 100% of 2,861,763 None.
Contact.enrich Who is this person now: title, employer, seniority and where they are? About 20¢ per 100 contacts 99.99% of 136,987 Title, employer, seniority and location, The full profile with past roles
ContactPoint.findEmail What is this person’s work email? About 0.45¢ an address found 95% of 3,296,127 None.
ContactPoint.findPhone What is this person’s direct phone number? About 1.7¢ a number found 92.9% of 1,002,342 None.
Prospect.find Who at these companies do I talk to? About 3.8¢ per 100 rows 99.99% of 636,024 People by title, or at a company domain, People at companies that match an industry, keywords or size, The person to write to at each company, People who fit a sentence, Creators by audience, People who engaged with a post
ContactPoint.verifyEmail Is this address real, and is it safe to send to? About 18¢ per 100 addresses 99.99% of 2,098,997 Check the mailbox, A second opinion on a catch-all
Prospect.verify Can I reach this person, and is the address safe to send to? About 0.6¢ a verified address 94.9% of 2,098,997 Find the work email, Check the mailbox, Find a direct phone

The word you searched for is one of these calls

You searched for The call
Company search, account list Organization.find
Total addressable market, market size Organization.count
Lookalike companies Organization.find
Company enrichment, firmographics Organization.enrich
Technographics, what software a company uses Organization.enrich
Buying triggers, funding news, hiring news Organization.enrich
Website visitor identification, reverse IP Organization.resolve
People search, contact search Prospect.find
Email finder ContactPoint.findEmail
Email verification ContactPoint.verifyEmail
Catch-all verification ContactPoint.verifyEmail
Phone finder, direct dials ContactPoint.findPhone
Contact enrichment Contact.enrich
Keyword research, keyword ideas Keyword.find
Competitor keywords Keyword.find
Competitor PPC keywords Keyword.find
Search volume, CPC Keyword.measure
Keyword difficulty Keyword.measure
PPC forecast, Keyword Planner forecast Keyword.forecast
SERP, search results Keyword.search
Social listening, brand mentions Keyword.search
AEO rankings, AI visibility, GEO Keyword.ask
Domain authority Domain.benchmark
Competitor analysis Domain.findCompetitors
Backlinks Domain.findLinks
Link gap, link intersect Domain.findLinks
Index status, indexing check Domain.verify
SEO audit of one page Page.audit
Site audit, site crawl Site.audit
Ad library, competitor ads Ad.find
Rank tracking Monitor.create

Every data call keeps the same contract

Every row says where it came from. Each row carries observedAt, method (sampled, estimated or reported) and, where it has them, venue and locale. The Observed type is the same on every call.

A blank is unknown, never zero. Long-tail terms often have no volume reading; that reads searches: null. A 0 means the source measured zero.

You pay per result returned. Never per row asked for, and never a one-row minimum on an empty answer. Counting is free. A miss is free wherever a route allows it: an email or phone find that finds nothing, and a check that ends catch-all or unknown.

Every call has a cap. maxCost defaults per call. A call that would pass it is refused before it spends, or stops early and returns what it has. Every response carries cost: what it spent, the most it could have, the units billed and the misses.

Falling back is the platform’s job. On a 429, a 5xx or a timeout the next route answers, and you pay for one. A 4xx is never retried elsewhere: the input is wrong, so the call says so.

A filter is applied or listed. A filter no route can apply comes back in ignored, never silently dropped. Send strict: true to be refused instead, at $0. Filter coverage shows how often each one applies.

Readings are reused. A reading younger than maxAge returns at $0. Market readings (volume, results pages, authority, links) are shared across startups for the same subject and locale; readings about people never are.

Every call emits one Event. Its data holds the rows, so a Trigger can fire on it and Metric.query can read it back. In try mode the read runs and returns real rows, and nothing is saved or billed.

Every response
{
  "mode": "try",
  "stored": false,
  "api": "https://api.sb/leaseline.app",
  "action": { "$id": "https://api.sb/leaseline.app/actions/action_KO1jlJbtig", "operation": "Organization.find", "status": "done" },
  "organizations": [ "…the call's own value, documented on its page" ],
  "links": { "next": "https://api.sb/leaseline.app/organizations/find?after=org_9Qe2" }
}

Ten calls a second per key, and an array counts as one

BehaviorRule
Rate10 calls a second and 600 a minute, per key, per call. Over it, a 429 with Retry-After.
BatchAn array input (keywords, hostnames, addresses) counts as one call, up to the call’s stated maximum, under one maxCost and one cost.
PagesA list returns after and total when the source knows it. limit defaults to 25 and tops out at 100 a page unless the call says otherwise.
AsyncA call whose median run is over 10 seconds, such as an AI answer or a site crawl, returns a pending Action in send mode; its Event delivers the result.
IdempotencyThe same Idempotency-Key with the same input replays the first answer at $0; with other input it returns 409.

When a call says no, it names the fix and the next call

Every refusal is the hub’s RFC 9457 problem, served as application/problem+json: type, title, status, detail, fix, next (the call that clears it, with its input) and instance. Nothing is spent on a refusal. A miss is not a refusal: it returns 200 with the field null.

A max-cost refusal
{
  "type": "https://startupbuilder.dev/errors/max-cost",
  "title": "The call would spend more than its cap",
  "status": 422,
  "detail": "100 rows from a sentence cost about $0.20; maxCost is $0.05.",
  "fix": "Lower limit, or raise maxCost to the price the detail quotes.",
  "next": { "verb": "Organization.find", "input": { "question": "US property managers with 20 to 400 units who still track rent in spreadsheets", "limit": 25, "maxCost": 0.05 } },
  "instance": "https://api.sb/leaseline.app/actions/action_Pq7wD2"
}
CodeStatusRefuses whenFixThen call
filter-unsupported422a call sent with strict: true and a filter no route can applyDrop that filter, or send without strict and read what comes back in ignored.Organization.count
input-missing422a data call given none of the input sets that name its subject, such as a person’s name without their company’s domainSend one of the input sets the call’s Inputs table lists; nothing was spent.Organization.resolve
limit-exceeded422any data call once the startup’s monthly usage Limit for data is spentRaise the Limit once an Approval allows it, or wait for the month to reset.Limit.raise
max-cost422a data call whose price for what you asked is above its maxCost, checked before anything is spentLower limit, or raise maxCost to the price the refusal’s detail quotes.Organization.find
rate-limited429more than 10 calls a second, or 600 a minute, to one call on one keyWait the Retry-After seconds and retry; an array input counts as one call.Action.retry
sources-busy503a call whose every route failed or is out of capacity; nothing is spentRetry after retryAfter with the same Idempotency-Key, or send it and watch for the Event.Action.retry
venue-unsupported422a search engine, answer engine or network the call does not read, such as ChatGPT sent to Keyword.measurePick one the call’s venue input lists; AI answers are Keyword.ask, posts are Keyword.search.Keyword.ask

Test values answer the same way every time, for free

A sk_test_ key answers these subjects the same way on every call, at $0, so an agent’s branches can be tested before a live key spends anything. Each call’s page repeats its own rows under Example.

Test value Call Always returns What it is for
headline: 'test: disapprove' Ad.create Refuses: venue-rejected The test ad account rejects it at review with the reason Misleading claims, passed through in detail, so your agent’s rewrite path runs.
query: 'test = suppressed-member' Audience.create Refuses: audience-guard One of its three test members sits on a Suppression, so nothing uploads until that member leaves the query.
venue: 'linkedin' under sk_test_ Campaign.create {"state":"draft","outside":{"linkedin":"test-campaign-1"}} Opens a Campaign on a test ad account that never serves or spends, and returns the same campaign id every time.
budget: { amount: 999999, currency: 'USD' } Campaign.create Refuses: over-mandate A $999,999 budget is over the Limit of every test standing approval, so the call refuses before a Campaign or a Bill exists.
campaign_test_linkedin Campaign.update Refuses: over-mandate A raise to $999,999 is over the Limit of every test standing approval, so it refuses and the test Campaign keeps its budget.
metric: 'test-flat' Metric.query {"rows":[{"value":7,"series":[1,1,1,1,1,1,1],"readable":true}]} One a day for seven days, every time, so a readout or a stop rule can be tested against a known line.
lead_test_strong Lead.qualify {"fit":"strong","deal":{"status":"Open","value":{"amount":1788,"currency":"USD"}}} A strong-fit test lead opens the same $1,788 deal every time, so your pipeline steps run against a known value.
limit: { amount: { amount: 1000000, currency: 'USD' } } Mandate.authorize {"status":"active","limit":{"amount":{"amount":5000,"currency":"USD"}}} A test authorizer holds a $5,000 spend Permission, so a wider Limit comes back narrowed to it: a standing approval never widens a Permission.
int_test_needs_reauth Integration.call Refuses: needs-reauth Every call through it answers as if the account had ended the sign-in, so your reconnect path runs.
int_test_x Integration.call Refuses: grant-missing It holds only the post-and-reply grant, so a call to change follows refuses before it leaves the platform.
int_test_revoked Handle.connect Refuses: account-not-connected The Integration reads revoked, so the bind refuses before any call leaves the platform.
venue: 'gmail' under sk_test_ Integration.connect {"state":"connected","environment":"test","account":"inbox@leaseline.test"} Skips the approval page and returns a connected test Integration that reaches no real mailbox, so the calls after it run end to end.
audience_test_waitlist Message.broadcast {"counts":{"audience":4,"sending":3,"skippedNoConsent":0,"skippedSuppressed":1}} Four test Contacts, one of them on a Suppression, so your agent sees the skip without sending to anyone.
audience_test_spam_rate Message.broadcast Refuses: spam-brake Sends as if the Domain’s complaint rate were over the brake, so the broadcast refuses and nothing goes out.
msg_test_unwarmed Message.schedule Refuses: mailbox-warm Its Mailbox is on day 6 of a 14-day warm-up, so the first cold email holds until the warm-up ends.
contact_test_busy Meeting.book Refuses: availability Its test calendar is busy every weekday from 2:00 to 3:00 p.m. Central, so a booking then refuses and names the next free slot.
contact_test_active Contact.enroll {"status":"active","step":"email-1","exitReason":null} Enrolls and renders the first step without sending, so your agent can read the run it starts.
contact_test_suppressed Contact.enroll Refuses: suppressed-contact The address sits on a Suppression, so the enroll refuses before any step is planned.
contact_test_no_consent Contact.enroll Refuses: no-consent The Contact gave no Consent for the Sequence’s purpose, so the enroll refuses.
post_test_published Post.publish {"status":"published","outside":{"linkedin":"urn:li:share:7000000000000000001"}} Publishes to a test account and returns the same network id every time, so your agent’s follow-up steps run.
post_test_unresolved Post.publish Refuses: claims-resolve Its one claim names no live record, so the publish refuses before anything reaches the network.
post_test_removed Post.publish Refuses: venue-rejected The network takes the Post down as it goes live, and its reason comes back in detail, so your removal path runs.
post_test_launch Post.schedule {"status":"scheduled","publishAt":"2026-11-04T08:01:00Z"} Queues on a test account and never publishes, so a launch-day Workflow runs end to end before the real one.
US property managers with 20 to 200 staff Organization.count {"count":4180,"ignored":[]} The market Leaseline sells to counts 4,180 companies, every time, for free.
harborview-pm.com Organization.enrich {"name":"Harborview Property Management","hostname":"harborview-pm.com","industry":"Real estate","headcount":34,"founded":2009,"country":"US","region":"US-WA"} Enriches to the same Harborview profile every time: 34 staff, founded 2009, in Washington.
dana@harborview-pm.com ContactPoint.verifyEmail {"result":"deliverable","catchAll":false,"role":false} Always deliverable: a person’s own mailbox that accepts mail.
leasing@crestline-residential.com ContactPoint.verifyEmail {"result":"catch-all","catchAll":true,"role":true} Always catch-all: the domain accepts every address, so the check cannot confirm this one, and it costs nothing.
former.manager@harborview-pm.com ContactPoint.verifyEmail {"result":"invalid","catchAll":false,"role":false} Always invalid: the mailbox does not exist, as when someone has left the company.
office@quietpine-rentals.test ContactPoint.verifyEmail {"result":"unknown","catchAll":null,"role":true} Always unknown: the mail server never answered, so check again with depth deep; it costs nothing.
rent ledger template Keyword.measure {"term":"rent ledger template","searches":1900,"cpc":2.4,"difficulty":18,"intent":"learn","trend":"rising"} 1,900 searches a month, $2.40 a click and difficulty 18, every time.
maxCost: 0.0001 Any priced call Refuses: max-cost Any priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap.
rate-limited.test Any priced call Refuses: rate-limited Any call naming this hostname answers 429 with Retry-After, so your retry logic runs.
sources-busy.test Any priced call Refuses: sources-busy Any call naming this hostname answers 503 as if every route were busy, and nothing is spent.

Read what you measured with one query

Answer share and rank curves are not calls of their own. They are Metric.query over the Events these calls emit: a week of Keyword.asked split by site is your answer share on each engine, and a month of Keyword.searched for one term is its rank curve.

Answer share by engine, week by week
import { $ } from 'startup-builder'

const share = await $.Metric.query({ event: 'Keyword.asked', shape: 'trend', breakdown: 'venue', window: '8w' })

The calls compose into Workflows, agent tasks and Services

Each Workflow, agent task and Service names its steps as these calls, so its price is the sum of the prices printed here. The accounts your agents act through are Integrations, and the shared Types say what every field means.

Contents