curl -X POST https://api.dataforb2b.ai/search/reasoning \
-H "api_key: YOUR_api_key" \
-H "Content-Type: application/json" \
-d '{
"query": "Heads of Sales at French fintech scale-ups",
"category": "people",
"max_results": 25
}'
import requests
BASE = "https://api.dataforb2b.ai"
HEADERS = {"api_key": "YOUR_api_key", "Content-Type": "application/json"}
resp = requests.post(f"{BASE}/search/reasoning", headers=HEADERS, json={
"query": "Heads of Sales at French fintech scale-ups",
"category": "people",
"max_results": 25,
}).json()
# Answer clarifying questions if the agent asks
while resp["status"] == "needs_input":
answers = {q["id"]: q["suggestions"][0] for q in resp["questions"]}
resp = requests.post(f"{BASE}/search/reasoning", headers=HEADERS, json={
"session_id": resp["session_id"],
"answers": answers,
}).json()
print(f"{resp['total']} results — {resp['credits_used']} credits")
const BASE = 'https://api.dataforb2b.ai';
const headers = { api_key: 'YOUR_api_key', 'Content-Type': 'application/json' };
let resp = await fetch(`${BASE}/search/reasoning`, {
method: 'POST',
headers,
body: JSON.stringify({
query: 'Heads of Sales at French fintech scale-ups',
category: 'people',
max_results: 25
})
}).then(r => r.json());
// Answer clarifying questions if the agent asks
while (resp.status === 'needs_input') {
const answers = Object.fromEntries(
resp.questions.map(q => [q.id, q.suggestions?.[0] ?? ''])
);
resp = await fetch(`${BASE}/search/reasoning`, {
method: 'POST',
headers,
body: JSON.stringify({ session_id: resp.session_id, answers })
}).then(r => r.json());
}
console.log(`${resp.total} results — ${resp.credits_used} credits`);
{
"status": "needs_input",
"session_id": "rs_8f2c1a9b",
"reasoning": "Fintech scale-up can mean different sizes — let me confirm.",
"questions": [
{
"id": "company_size",
"text": "What company size do you consider a scale-up?",
"suggestions": ["51-200", "201-500", "501-1000"]
}
]
}
{
"status": "complete",
"session_id": "4d84740e1a654105b4af9ffe403f6c3f",
"reasoning": "Targeted Heads/VPs/Directors of Sales (and close variants like CRO) at French fintech companies via category + country + title variants. 55 matches.",
"questions": null,
"applied_filters": {
"op": "and",
"conditions": [
{
"op": "or",
"conditions": [
{"column": "current_title", "type": "like", "value": "head of sales"},
{"column": "current_title", "type": "like", "value": "vp sales"},
{"column": "current_title", "type": "like", "value": "chief revenue officer"}
]
},
{"column": "current_company_category", "type": "=", "value": "fintech"},
{"column": "profile_country", "type": "=", "value": "FR"}
]
},
"total": 55,
"count": 25,
"has_next_page": true,
"credits_used": 20.75,
"results": [
{
"id": "prof_PVZvTCRqnvSOWWfQOav9QQI130aGcZuo4Lez",
"first_name": "Loic",
"last_name": "Jaume",
"headline": "Head of Sales at Linedata",
"location": "Greater Paris Metropolitan Region",
"country": "FR",
"industry": "Computer Software",
"summary": null,
"profile_language": "en_US",
"profile_picture_url": null,
"links": {
"linkedin": "https://www.linkedin.com/in/loic-jaume-3894a98",
"twitter": null,
"github": null
},
"experience": ["..."],
"education": ["..."],
"skills": ["..."],
"certifications": ["..."],
"languages": ["..."],
"metrics": {"followers": 1200, "skills_count": 14}
}
]
}
AI Search
Reasoning Search
Multi-turn AI agent that builds and runs the best possible search for you
POST
/
search
/
reasoning
curl -X POST https://api.dataforb2b.ai/search/reasoning \
-H "api_key: YOUR_api_key" \
-H "Content-Type: application/json" \
-d '{
"query": "Heads of Sales at French fintech scale-ups",
"category": "people",
"max_results": 25
}'
import requests
BASE = "https://api.dataforb2b.ai"
HEADERS = {"api_key": "YOUR_api_key", "Content-Type": "application/json"}
resp = requests.post(f"{BASE}/search/reasoning", headers=HEADERS, json={
"query": "Heads of Sales at French fintech scale-ups",
"category": "people",
"max_results": 25,
}).json()
# Answer clarifying questions if the agent asks
while resp["status"] == "needs_input":
answers = {q["id"]: q["suggestions"][0] for q in resp["questions"]}
resp = requests.post(f"{BASE}/search/reasoning", headers=HEADERS, json={
"session_id": resp["session_id"],
"answers": answers,
}).json()
print(f"{resp['total']} results — {resp['credits_used']} credits")
const BASE = 'https://api.dataforb2b.ai';
const headers = { api_key: 'YOUR_api_key', 'Content-Type': 'application/json' };
let resp = await fetch(`${BASE}/search/reasoning`, {
method: 'POST',
headers,
body: JSON.stringify({
query: 'Heads of Sales at French fintech scale-ups',
category: 'people',
max_results: 25
})
}).then(r => r.json());
// Answer clarifying questions if the agent asks
while (resp.status === 'needs_input') {
const answers = Object.fromEntries(
resp.questions.map(q => [q.id, q.suggestions?.[0] ?? ''])
);
resp = await fetch(`${BASE}/search/reasoning`, {
method: 'POST',
headers,
body: JSON.stringify({ session_id: resp.session_id, answers })
}).then(r => r.json());
}
console.log(`${resp.total} results — ${resp.credits_used} credits`);
{
"status": "needs_input",
"session_id": "rs_8f2c1a9b",
"reasoning": "Fintech scale-up can mean different sizes — let me confirm.",
"questions": [
{
"id": "company_size",
"text": "What company size do you consider a scale-up?",
"suggestions": ["51-200", "201-500", "501-1000"]
}
]
}
{
"status": "complete",
"session_id": "4d84740e1a654105b4af9ffe403f6c3f",
"reasoning": "Targeted Heads/VPs/Directors of Sales (and close variants like CRO) at French fintech companies via category + country + title variants. 55 matches.",
"questions": null,
"applied_filters": {
"op": "and",
"conditions": [
{
"op": "or",
"conditions": [
{"column": "current_title", "type": "like", "value": "head of sales"},
{"column": "current_title", "type": "like", "value": "vp sales"},
{"column": "current_title", "type": "like", "value": "chief revenue officer"}
]
},
{"column": "current_company_category", "type": "=", "value": "fintech"},
{"column": "profile_country", "type": "=", "value": "FR"}
]
},
"total": 55,
"count": 25,
"has_next_page": true,
"credits_used": 20.75,
"results": [
{
"id": "prof_PVZvTCRqnvSOWWfQOav9QQI130aGcZuo4Lez",
"first_name": "Loic",
"last_name": "Jaume",
"headline": "Head of Sales at Linedata",
"location": "Greater Paris Metropolitan Region",
"country": "FR",
"industry": "Computer Software",
"summary": null,
"profile_language": "en_US",
"profile_picture_url": null,
"links": {
"linkedin": "https://www.linkedin.com/in/loic-jaume-3894a98",
"twitter": null,
"github": null
},
"experience": ["..."],
"education": ["..."],
"skills": ["..."],
"certifications": ["..."],
"languages": ["..."],
"metrics": {"followers": 1200, "skills_count": 14}
}
]
}
An AI agent reasons about your query, probes the database in real time, asks clarifying questions when needed, then runs the best final search. Unlike a one-shot search, Reasoning Search is conversational: you can answer questions and refine results across turns using the same
Clarification turns (
The three
A real stream looks like this:
session_id.
Credit Cost
| Item | Credits |
|---|---|
| Agent fee (per completed search) | 2 credits |
| Result | 0.75 credits per result |
status: "needs_input") are free — the agent fee is only charged when a search actually runs.
Request Body
string
Natural language query (max 3000 characters). Required on the first call. On follow-up calls with a
session_id, use it to refine the previous search (e.g. "now only in San Francisco").string
Session identifier returned by a previous call. Send it back to answer questions or refine the same search.
object
Answers to the questions of a
needs_input turn, as {question_id: answer}.string
default:"people"
What to search:
"people" or "companies".integer
default:"25"
Number of results for the final search (1–100).
Pagination: this endpoint always returns the first
max_results results. To get the next pages, take the applied_filters from the response and call /search/people or /search/companies with them, setting offset (e.g. offset: 25, offset: 50, …). You only pay the agent fee once — pagination is billed at the standard per-result rate.Flow
1
Send your query
POST /search/reasoning with query. The response is either complete (results) or needs_input (questions).2
Answer questions (if asked)
Send back
session_id + answers. The agent continues and returns results.3
Refine (optional)
Send
session_id + a new query to refine the same search — the agent remembers the conversation.Show the agent’s reasoning live (recommended)
POST /search/reasoning/stream takes the exact same body but returns Server-Sent Events, so your users see the agent think, probe the database and build the search in real time — instead of staring at a spinner for 20–60 seconds.
Events arrive in this order:
| Event | Payload | When |
|---|---|---|
step | {type: "thought" | "action" | "observation", ...} | Each reasoning step, live |
questions | {session_id, reasoning, questions} | The agent needs clarification |
result | {session_id, reasoning, applied_filters, category, total, count, has_next_page, credits_used, results} | Final results |
error | {message} | Something went wrong |
done | {} | Always last — close the stream |
step types map naturally to UI elements:
thought—{type, text}: the agent’s narration. Render as a status line.action—{type, tool, filters?, resolve?}: a database probe about to run (resolve_value,find_companies,probe_count,preview_results, then a finalsearch).filtersshows the exact filters being tested.observation—{type, tool, result}: the probe’s outcome, e.g.{"count": 183}for aprobe_count.
POST isn’t supported by EventSource, consume the stream with fetch:
const res = await fetch('https://api.dataforb2b.ai/search/reasoning/stream', {
method: 'POST',
headers: { api_key: 'YOUR_api_key', 'Content-Type': 'application/json' },
body: JSON.stringify({ query: 'CTOs of AI startups in Paris', max_results: 25 })
});
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
let buffer = '';
while (true) {
const { value, done } = await reader.read();
if (done) break;
buffer += value;
// SSE frames are separated by a blank line
const frames = buffer.split('\n\n');
buffer = frames.pop(); // keep the incomplete frame
for (const frame of frames) {
const event = frame.match(/^event: (.+)$/m)?.[1];
const data = JSON.parse(frame.match(/^data: (.+)$/m)?.[1] ?? '{}');
if (event === 'step' && data.type === 'thought') showStatus(data.text);
if (event === 'step' && data.type === 'observation') showProbe(data.tool, data.result);
if (event === 'questions') askUser(data.session_id, data.questions);
if (event === 'result') showResults(data);
if (event === 'error') showError(data.message);
}
}
Python
import json, requests
with requests.post(
"https://api.dataforb2b.ai/search/reasoning/stream",
headers={"api_key": "YOUR_api_key", "Content-Type": "application/json"},
json={"query": "CTOs of AI startups in Paris", "max_results": 25},
stream=True,
) as r:
event = None
for line in r.iter_lines(decode_unicode=True):
if line.startswith("event: "):
event = line[7:]
elif line.startswith("data: "):
data = json.loads(line[6:])
if event == "step":
print(f"[{data['type']}] {data.get('text') or data.get('tool')}")
elif event == "result":
print(f"Done: {data['total']} results, {data['credits_used']} credits")
event: step
data: {"type": "action", "tool": "resolve_value", "resolve": {"type": "category", "q": "artificial intelligence"}}
event: step
data: {"type": "observation", "tool": "resolve_value", "result": {"matches": [{"value": "artificial intelligence", "popularity": "10k-100k"}]}}
event: step
data: {"type": "action", "tool": "find_companies", "filters": {"op": "and", "conditions": [...]}}
event: step
data: {"type": "observation", "tool": "find_companies", "result": {"total": 680, "returned": 680}}
event: step
data: {"type": "action", "tool": "probe_count", "filters": {"op": "and", "conditions": [...]}}
event: step
data: {"type": "observation", "tool": "probe_count", "result": {"count": 183, "is_capped": false}}
event: step
data: {"type": "action", "tool": "search"}
event: result
data: {"session_id": "...", "reasoning": "Found 680 AI startups in Paris, then filtered CTOs (183 matches).", "total": 203, "count": 25, "credits_used": 20.75, "results": [...]}
event: done
data: {}
Response
string
"complete" (results below) or "needs_input" (answer the questions).string
Send it back to answer questions or refine the search.
string
Summary of what the agent searched for and why. May be
null on a needs_input turn.array
Only when
status is needs_input. Each question has id, text and optional suggestions (display them as choice chips in your UI).object
Only when
status is complete. The final filters built by the agent. You can reuse them directly on /search/people or /search/companies to paginate.integer
Total number of matching results.
integer
Number of results returned.
boolean
Whether more results exist beyond
max_results (paginate with applied_filters, see above).number
Total credits charged (agent fee + results).
array
Profiles or companies, same structure as
/search/people / /search/companies. People results also carry a relevance_score (0–1) and are ordered by relevance to your query.curl -X POST https://api.dataforb2b.ai/search/reasoning \
-H "api_key: YOUR_api_key" \
-H "Content-Type: application/json" \
-d '{
"query": "Heads of Sales at French fintech scale-ups",
"category": "people",
"max_results": 25
}'
import requests
BASE = "https://api.dataforb2b.ai"
HEADERS = {"api_key": "YOUR_api_key", "Content-Type": "application/json"}
resp = requests.post(f"{BASE}/search/reasoning", headers=HEADERS, json={
"query": "Heads of Sales at French fintech scale-ups",
"category": "people",
"max_results": 25,
}).json()
# Answer clarifying questions if the agent asks
while resp["status"] == "needs_input":
answers = {q["id"]: q["suggestions"][0] for q in resp["questions"]}
resp = requests.post(f"{BASE}/search/reasoning", headers=HEADERS, json={
"session_id": resp["session_id"],
"answers": answers,
}).json()
print(f"{resp['total']} results — {resp['credits_used']} credits")
const BASE = 'https://api.dataforb2b.ai';
const headers = { api_key: 'YOUR_api_key', 'Content-Type': 'application/json' };
let resp = await fetch(`${BASE}/search/reasoning`, {
method: 'POST',
headers,
body: JSON.stringify({
query: 'Heads of Sales at French fintech scale-ups',
category: 'people',
max_results: 25
})
}).then(r => r.json());
// Answer clarifying questions if the agent asks
while (resp.status === 'needs_input') {
const answers = Object.fromEntries(
resp.questions.map(q => [q.id, q.suggestions?.[0] ?? ''])
);
resp = await fetch(`${BASE}/search/reasoning`, {
method: 'POST',
headers,
body: JSON.stringify({ session_id: resp.session_id, answers })
}).then(r => r.json());
}
console.log(`${resp.total} results — ${resp.credits_used} credits`);
{
"status": "needs_input",
"session_id": "rs_8f2c1a9b",
"reasoning": "Fintech scale-up can mean different sizes — let me confirm.",
"questions": [
{
"id": "company_size",
"text": "What company size do you consider a scale-up?",
"suggestions": ["51-200", "201-500", "501-1000"]
}
]
}
{
"status": "complete",
"session_id": "4d84740e1a654105b4af9ffe403f6c3f",
"reasoning": "Targeted Heads/VPs/Directors of Sales (and close variants like CRO) at French fintech companies via category + country + title variants. 55 matches.",
"questions": null,
"applied_filters": {
"op": "and",
"conditions": [
{
"op": "or",
"conditions": [
{"column": "current_title", "type": "like", "value": "head of sales"},
{"column": "current_title", "type": "like", "value": "vp sales"},
{"column": "current_title", "type": "like", "value": "chief revenue officer"}
]
},
{"column": "current_company_category", "type": "=", "value": "fintech"},
{"column": "profile_country", "type": "=", "value": "FR"}
]
},
"total": 55,
"count": 25,
"has_next_page": true,
"credits_used": 20.75,
"results": [
{
"id": "prof_PVZvTCRqnvSOWWfQOav9QQI130aGcZuo4Lez",
"first_name": "Loic",
"last_name": "Jaume",
"headline": "Head of Sales at Linedata",
"location": "Greater Paris Metropolitan Region",
"country": "FR",
"industry": "Computer Software",
"summary": null,
"profile_language": "en_US",
"profile_picture_url": null,
"links": {
"linkedin": "https://www.linkedin.com/in/loic-jaume-3894a98",
"twitter": null,
"github": null
},
"experience": ["..."],
"education": ["..."],
"skills": ["..."],
"certifications": ["..."],
"languages": ["..."],
"metrics": {"followers": 1200, "skills_count": 14}
}
]
}

