Keyword .ask
Ask ChatGPT, Gemini, Perplexity and the other answer engines a buyer’s question and see whether they name you and which pages they cite.
- Price
- 0.4¢ an answer
- Success rate
- 99.96% of 131,093 calls
- Freshness
- Fresh for 7 days
- Emits
Keyword.asked- Capability
- Market data
POST https: //api.sb/ {your-domain}/ keywords/ ask
Options and prices
Inputs
| Name | Type | Default | Meaning |
|---|---|---|---|
keyword | string | Required | The question, worded as a buyer would type it to an assistant. |
venues | ('chatgpt' | 'gemini' | 'perplexity' | 'copilot' | 'claude' | 'google-ai-mode')[] | ['chatgpt', | The engines to ask, in parallel. Each is its own job with its own price. |
runs | number | 1 | Times to ask each engine, 1 to 3. Answers vary run to run, so a tracked question takes 3. |
country | string | your home Market | Where the question is asked from, signed out. |
brands | string[] | your Brand and your rivals | The brands mentioned reports on, named or cited. |
maxAge | string | '7d' | A stored reading younger than this returns at $0 instead of reading again. |
maxCost | number | 0.10 | The most this call may spend, in USD. Over it, the call is refused before it spends, or stops early with what it has. |
Outputs
| Field | Type | What null means |
|---|---|---|
keyword | string | Never null. |
answers | Answer[] | Never null: one per engine per run. |
answers[].venue | VenueId | Never null. |
answers[].run | number, in 1 to 3 | Never null. |
answers[].text | string | Never null: the answer as shown. |
answers[].named | { brand: | Never null: brands in order of first mention; empty when none is named. |
answers[].cited | { position: | Never null: empty when the engine cites nothing. |
answers[].queries | string[] | Never null: the searches the engine ran, empty when it does not show them. |
answers[].mentioned | { brand: | Never null: one row per brand in brands. |
answers[] | Observed | Each answer also carries observedAt, method and locale. |
cost | Cost, in USD | Never null. In try mode usd is 0 and maxUsd is what the call would have cost. |
Read the result
| Field | Value | What it means | What to do |
|---|---|---|---|
runs | 1 | One answer is an anecdote: the same engine names different brands on the next run. | Ask a tracked question 3 times on each engine. (the answer-share sampling rule) |
mentioned.named | Share across 200 answers | At a 10% share, 200 answers read ±4.2 points. | Flag only a move of 5 points or more that holds for 2 weeks; anything less is noise. (binomial interval, the strategy numbers) |
cited | Reddit threads on Perplexity, encyclopedic pages on ChatGPT | Engines cite different sources: Reddit is 46.7% of Perplexity’s top-10 cited domains, and only about 11% of domains are cited by both. | Read each engine on its own and plan per engine; never blend them into one score. (a study of about 680M citations) |
mentioned.cited | false everywhere | Branded mentions on the web track AI visibility more closely (0.664) than referring domains do (0.295). | Get listed and mentioned on the pages engines already cite before you build links. (a correlation study of 75,000 brands) |
queries | Searches the engine ran | The engine looked these up before it answered. | Measure them with Keyword.measure; a page that ranks for them gets cited. (the AEO playbook) |
Effects
- Action class
None: it reads, so no approval rule names it
- Modes
try: Asks the engines and returns real answers; nothing is saved and nothing is billed.send: Returns a pending Action at once;Keyword.askedcarries the answers when every engine has replied.do: Waits about 30 seconds for every engine, then returns the answers, billed per answer.
- Idempotency
The same
Idempotency-Keywith the same input replays the first answers at $0; with other input it returns 409.- Saved or shared
Nothing is written to your records. Answers are shared across startups for the same question, engine and country for 7 days;
mentionedis yours.- Emits
Keyword.askedwith{ keyword,venue, run, named, cited, mentioned }, one Event per answer - Performed by
- Price
About 0.4¢ an answer. Free: an answer younger than
maxAge.maxCostdefaults to 10¢. 20 buying questions on 4 engines: 80 × 0.4¢ an answer is about 32¢.- Reliability
The first route succeeds 99.96% of 131,093 calls. If it fails, a second route answers at 97.9% of 109,468 calls, and you pay for one.
- Freshness
A reading younger than 7 days returns at $0. Readings are shared across startups for the same subject and locale.
- Batch and pages
Up to 18 answers a call: 6 engines × 3 runs. An answer takes about 30 seconds, so
sendreturns a pending Action at once andKeyword.askeddelivers the answers- Rate
The shared rate rules: 10 calls a second per key, and an array input counts as one call.
Refuses when
| Check | Error | Fix | Then call |
|---|---|---|---|
A search engine, answer engine or network the call does not read, such as ChatGPT sent to Keyword.measure | venue-unsupported | Pick one the call’s venue input lists; AI answers are Keyword.ask, posts are Keyword.search. | Keyword.ask |
Every data call can also meet the shared data-call refusals: filter-unsupported, input-missing, limit-exceeded, max-cost, rate-limited, sources-busy.
The venue-unsupported payload
{
"type": "https://startupbuilder.dev/errors/venue-unsupported" ,
"title": "The call does not read that search engine or network",
"status": 422,
"detail": "A search engine, answer engine or network the call does not read, such as ChatGPT sent to `Keyword.measure`." ,
"fix": "Pick one the call’s `venue` input lists; AI answers are `Keyword.ask`, posts are `Keyword.search`." ,
"next": {
"verb": "Keyword.ask",
"input": {
"keyword": "best rent tracking software for a 40-unit property manager",
"venues": [
"chatgpt"
]
}
},
"instance": "https://api.sb/leaseline.app/actions/action_1"
}When it waits
| Fact | Value |
|---|---|
send returns | A pending Action, status:, with its $id. |
| Delivered by | Keyword.asked |
await $.Watch.create({
selector: 'Keyword.asked',
url: 'https://leaseline.app/hooks/answers' ,
})Example
Do ChatGPT and Perplexity name Leaseline when a 40-unit property manager
asks for rent tracking software? Spend up to 2¢. To retry, send the same Idempotency-Key: the retry returns the first answer for $0. A new key reads again.
Test values, and watching it
A sk_test_ key answers these the same way every time, at $0 (every test value).
| Test value | Always returns | What it is for |
|---|---|---|
maxCost: | Refuses with 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 | Refuses with rate-limited | Any call naming this hostname answers 429 with Retry-After, so your retry logic runs. |
sources-busy.test | Refuses with sources-busy | Any call naming this hostname answers 503 as if every route were busy, and nothing is spent. |
Watch it on a schedule: a Monitor runs this call and records an Event only when the reading changes.
await $.Monitor.create({
verb: 'Keyword.ask',
input: { keyword: 'best rent tracking software for a 40-unit property manager', runs: 3 },
change: 'answer-citation',
every: '1w',
})Used by
- Workflows: AI answer audit · Search readout
- Agent tasks: Answer page per question · Monthly search content
- Jobs: Check AI answers · Measure