The analyze API
POST /v1/analyze — the stateless synthesis over a set you provide. One call, synchronous, a few seconds. Authenticated with x-api-key.
Request
Provide a set of 3–50 companies, one of two ways:
| Field | Type | Notes |
|---|---|---|
texts |
{ name, text }[] |
Raw clean text per company (≤ 50,000 chars each). Classified server-side. The simplest path. |
companies |
ClassifiedCompany[] |
Pre-classified via the classify schema. Cheapest — skips server-side classification. |
focal |
string |
Optional. A company name to center the read on. |
axes |
FieldAxis[] |
Optional. Re-map the set onto a given frame instead of deriving one. The diff enabler — see below. |
Provide either texts or companies (at least 3). A set of one or two can’t form a field.
curl -X POST https://api.stratless.com/v1/analyze \
-H "x-api-key: sk_live_…" \
-H "content-type: application/json" \
-d '{
"texts": [
{ "name": "Pinecone", "text": "…" },
{ "name": "Qdrant", "text": "…" },
{ "name": "Weaviate", "text": "…" }
],
"focal": "Pinecone"
}'import requests
res = requests.post(
"https://api.stratless.com/v1/analyze",
headers={"x-api-key": "sk_live_…"},
json={
"texts": [
{"name": "Pinecone", "text": "…"},
{"name": "Qdrant", "text": "…"},
{"name": "Weaviate", "text": "…"},
],
"focal": "Pinecone",
},
)
result = res.json()const res = await fetch("https://api.stratless.com/v1/analyze", {
method: "POST",
headers: { "x-api-key": "sk_live_…", "content-type": "application/json" },
body: JSON.stringify({
texts: [
{ name: "Pinecone", text: "…" },
{ name: "Qdrant", text: "…" },
{ name: "Weaviate", text: "…" },
],
focal: "Pinecone",
}),
})
const result = await res.json()Response
A uniform envelope: { success, requestId, data, meta }. meta carries { count, cost } (cost = companies analyzed = credits spent). data is the field map:
| Field | Type | Meaning |
|---|---|---|
coherent |
boolean |
Is this one field, or a grab-bag? If false, stratless stops honestly rather than fabricate a field. |
coherence_note |
string |
Why it’s coherent (or not). |
axes |
FieldAxis[] |
Up to 3 determinant, independence-checked choices the market varies on. |
axes_source |
'derived' | 'provided' |
Whether stratless derived the frame or you passed one. |
independence |
{ score, label } |
How un-correlated the axes are across the set (ok / weak). |
distribution |
Record<axis, Record<value, count>> |
Per-axis value counts — factual density. |
companies |
PlacedCompany[] |
Each company’s coordinates, rivals, provenance, and confidence. |
clusters |
Cluster[] |
Who occupies the same strategic position. |
robustness |
{ score, label } |
Cluster stability — two-signal agreement (high / moderate / low). |
white_space |
Read[] |
Empty positions, each a hypothesis with the barrier named — never “opportunity.” |
convergence |
Read[] |
Crowded positions. |
focal |
FocalRead? |
Present when you passed focal. |
dropped |
{ name, page_type, note }[] |
Companies that couldn’t be placed, and why. |
meta.calibration |
{ remap, provisional } |
The receipt behind every confidence.score. |
Types
FieldAxis = { key, label, values: string[], rationale }
PlacedCompany = {
name, coords: Record<string, string>,
nearest: NearestRel[],
basis, reliability, // provenance: what it was read from
confidence: { label: 'high' | 'moderate' | 'low', score: number | null }
}
NearestRel = { name, sim, confidence: 'high' | 'low' } // high = direct, low = indirect
Read = { where: Record<string, string>, note, barrier? }
Confidence is measured, not asserted
Each placement’s confidence.label is a bucket; its score is that bucket’s measured accuracy against expert-labeled maps — currently high ≈ 0.897, moderate ≈ 0.846. The score is a bucket frequency, not a per-placement probability, and it’s provisional until more fields are labeled. meta.calibration ships the receipt. A nearest rival is high (direct) only when the similarity clears a calibrated bar and is reciprocal — two witnesses.
Determinism and the diff
Everything runs at temperature 0. Pass a previous run’s axes back in, and both maps share a coordinate system — so you can diff them without storing anything. That’s the stateless delta: the caller holds the two runs, stratless holds nothing.
Errors
Errors use { success: false, requestId, error: { code, message, details? } }.
| Status | When |
|---|---|
401 |
Missing or invalid API key. |
402 |
Out of credits — details carries { limit, used, resetsAt }. |
422 |
Invalid input (e.g. fewer than 3 companies). |
429 |
Rate limited. |