Recipe: land your own research
Declare what you want to know, record what your harness observed, and have Spore hold its shape.
When your systems do the work, Spore still holds the shape of it. You declare the fields once, you run whatever you run, then you record the results — no placeholder launch to reconcile against. What Spore reports is what actually landed.
Declaring and recording are both free.
A field must be declared before anything can be recorded into it, and every value is checked against the type it was declared with. There is no naming rule to remember and no reserved prefix: a namespace you declare is yours, and the namespaces a Spore tool produces are the tool's.
Declare what you want to know
A namespace groups fields. Each field says what its values are, what they measure, how long they stay current, and what it means — which is what makes a later coverage report and a later filter possible.
{
"name": "icp",
"description": "How well a company fits our ideal customer profile.",
"fields": [
{
"name": "score",
"type": "number",
"unit": "points",
"dimension": "fit",
"freshnessDays": 90,
"description": "0-10; how well the company fits, judged from its site."
},
{
"name": "rationale",
"type": "string",
"description": "Why the score is what it is, in one sentence."
}
]
}curl -X POST https://www.spore.ee/api/v1/namespaces \
-H "Authorization: Bearer $SPORE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d @icp.jsonSend the same declaration again whenever your harness boots. A field you already declared is left alone, a new one is added, and a description or freshness you changed your mind about is updated. Nothing is removed by omission, and once a Fact references a field its name, type, unit, and dimension are fixed — the fix for a mistake is a new field.
Record what you observed
One call carries up to 200 observations about one Company. Send an Idempotency-Key so a
retry lands nothing twice.
{
"companyId": "7f9c2a14-3b6e-4d51-9a2f-1c8e5b0d47a3",
"fields": [
{
"field": "icp.score",
"value": 82,
"evidence": [
{
"kind": "url",
"url": "https://example.com/careers",
"excerpt": "We are hiring 6 SDRs this quarter."
}
]
},
{
"field": "icp.rationale",
"value": "Series A, hiring SDRs"
}
]
}curl -X POST https://www.spore.ee/api/v1/record \
-H "Authorization: Bearer $SPORE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d @results.jsonSay when you looked and found nothing
Record an absent Fact, and Coverage reports the field as checked rather than as a gap you still owe.
{
"companyId": "7f9c2a14-3b6e-4d51-9a2f-1c8e5b0d47a3",
"fields": [{ "field": "icp.score", "absent": true }]
}Set observedAt when you learned something about an earlier moment, and pin: true when
one observation should stay current no matter what lands later — pin: false releases it.
What you get back
Every observation is appended and nothing is edited. The newest observation becomes the current value, an older observation arriving late does not displace a newer one, and the history stays readable underneath.
Read it back with GET /api/v1/companies/{companyId}/facts: current values with their
producer, their evidence, whether the declaration's freshness has lapsed, and every
earlier observation. Your Facts carry your API key as their attribution, so a later read
can tell your harness's answer from Spore's. POST /api/v1/coverage asks the opposite
question over a set — which of the fields you care about are current, stale, checked-none,
or missing.