Documentation
Documentation

Overview

Spore docs

Start here

Getting startedInstall the CLIAuthentication and keys

Build

Search and filtersSegments and the loopEnrichment lifecycle

Recipes

Recipe: search to a live SegmentRecipe: enrich without a segmentRecipe: land your own research

Connect

Events

Account

Credits and billing

Reference

Conventions
API reference

Authentication and keys

Bearer authentication, exact capability and Operation access, expiration, rolling budgets, and key delegation.

The header

Every /api/v1 request authenticates with the same header:

Authorization: Bearer spore_sk_...

The bare key without the Bearer prefix is also accepted for clients that cannot set a scheme. Anything else is a 401. A key belongs to an organization. Everything it reads and spends is that organization's.

Capability scopes

Every key carries an explicit capability set. The console offers Observer (read-only), Researcher, and Operator presets, or Custom access for individual scopes. Presets do not include key management; select it explicitly only for a trusted administrator.

ScopeAuthority
company:readRead Companies and held Company data.
company:writeCreate, correct, and delete Companies.
company:unlockUnlock Legal entity data for Companies (priced).
search:runRun Commons searches (priced).
segment:readRead Segments and their members.
segment:writeCreate, update, and launch Segments (includes priced work).
enrich:readRead enrichment Jobs and results.
enrich:runStart Company enrichment (priced).
knowledge:writeRecord organization knowledge.
export:runExport held data. Export is free; Unlock remains the data gate.
wallet:readRead credit balances and transactions.
events:readRead activity events.
key:manageCreate and revoke organization API keys, subject to the delegation rules below.

A key missing the required scope receives a structured 403:

{
	"error": "scope_required",
	"message": "This API key does not carry the required capability scope.",
	"requiredScope": "search:run",
	"scopes": ["company:read", "segment:read"]
}

Exact Operation allowlist

Scopes and allowedOperations are independent gates: every request must pass both. Use exact Operation IDs from the Operation contract (the IDs shown in the console), not REST paths or wildcard patterns.

  • Omitted or null: all Operations permitted by the key's scopes, including future Operations under those scopes.
  • []: deny every Operation.
  • An array such as ["search"]: only those exact Operations, and only with their required scopes.

An allowlist never grants a missing scope. The Door refuses a disallowed Operation before input validation or idempotency replay; it cannot recover an earlier response through a now-disallowed Operation.

Expiration and console lifecycle

Organization owners and admins can mint keys in Organization → API keys → Create API key. Name the client, choose a preset or Custom access, and set the rolling budget and per-request cap for priced scopes. Open Show exact access to choose individual custom scopes, Allowed Operations, and Expires in (30, 60, 90, 180, or 360 days). Choose Only selected Operations with no checkboxes to deny all. Custom non-priced management keys have no spending bounds.

Copy the secret from the success step: it is shown once and cannot be recovered. Open the key's detail page to inspect scopes, allowlist, expiry, limits, rolling burn, and history. Owners/admins can Revoke API key there and confirm the Decision. Expired or revoked credentials cannot authenticate. Mint a replacement rather than expecting revocation to be reversible.

Mint and revoke with Operations

Key management is two free Operations: key-create (POST /api/v1/keys) and key-revoke (POST /api/v1/keys/{keyId}/revoke). Both require key:manage, the relevant Operation in any exact allowlist, and a creator who is still an owner/admin of the authenticated organization. A key cannot revoke another organization's key or its own parent or any transitive ancestor; ancestor revocation returns 403 key_ancestor_revocation_forbidden. Revoked ancestors remain in the delegation chain. Keys created before parent relationships were recorded have no recoverable historical ancestry.

Creation takes name, scopes, integer expirationDays from 1 to 360, optional nullable allowedOperations, and the existing budgetCredits, budgetPeriodDays, and maxRequestCredits bounds. Any priced scope requires finite bounds. For example, using a dedicated management key whose expiry is more than one day away:

curl https://www.spore.ee/api/v1/keys \
  -H "Authorization: Bearer $MANAGEMENT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: create-research-agent-1" \
  -d '{"name":"Research agent","scopes":["search:run"],"expirationDays":1,"allowedOperations":["search"],"budgetCredits":100,"budgetPeriodDays":1,"maxRequestCredits":10}'

The management caller must have no spending bounds: any per-request bound, rolling budget, or budget period refuses minting, so a leaked capped key cannot multiply its budget by creating children. An unbounded management key may grant requested scopes, including priced scopes with finite bounds; it is administrative authority, not a spending credential. Every child expires no later than its parent. A restricted parent must grant an explicit subset of its own Operation allowlist and cannot grant key:manage to a child.

The created secret is returned only on initial success. An idempotency replay returns 409, never the secret. Store it immediately; if lost, revoke that key and mint a replacement with a new idempotency key.

curl -X POST "https://www.spore.ee/api/v1/keys/$KEY_ID/revoke" \
  -H "Authorization: Bearer $MANAGEMENT_KEY" \
  -H "Idempotency-Key: revoke-research-agent-1"

Revoking an already revoked non-ancestor key succeeds without another policy change. Revocation blocks subsequent authentication; it is not cancellation of already admitted work.

Spend bounds

Bounds let you delegate work without handing an agent the whole balance. Any key with a priced scope must carry finite credit bounds.

maxRequestCredits caps the quoted cost of one request. budgetCredits caps net burn (debits minus refunds attributed to this key) over the preceding budgetPeriodDays days, from 1 to 365. Headroom returns as spend leaves that rolling window or is refunded. This is not a lifetime credit cap. A zero bound allows no positive-priced quote. Organization credit balance and other admission rules still apply independently.

Both refusals are 402 and carry the numbers that produced them:

{
	"error": "request_cap_exceeded",
	"message": "This call is quoted above this key's per-request cap.",
	"bound": 500,
	"required": 900
}
{
	"error": "key_budget_exhausted",
	"message": "This key has insufficient rolling-window headroom.",
	"bound": 5000,
	"available": 120,
	"required": 400,
	"periodDays": 30
}

required is the quoted cost of the refused call, bound the ceiling, available the remaining headroom, and periodDays the rolling window. A bound is only checked when set.

Quoting happens before work starts, so a refusal never leaves a half-run request behind and never charges anything.

Attribution

Every credit change records the key that caused it. GET /api/v1/wallet/transactions pages the ledger newest-first by opaque cursor, and each row carries apiKeyId — null for spend driven by a dashboard session or by the system.

curl "https://www.spore.ee/api/v1/wallet/transactions?apiKeyId=$KEY_ID&limit=50" \
  -H "Authorization: Bearer $SPORE_API_KEY"

Per-key burn is a filter, not a join. The ledger read is free, org-wide, and cursor-paged.

Install the CLI

Install the spore command line from npm, point it at a key, and write the spore index into your agent's instructions with spore init.

Search and filters

The company filter AST, the field vocabulary that defines it, and how canonical hashing makes an identical search free for 24 hours.

On this page

The headerCapability scopesExact Operation allowlistExpiration and console lifecycleMint and revoke with OperationsSpend boundsAttribution