API Reference - Entity Enricher Documentation

API Reference

The Entity Enricher REST API lets you enrich entities, manage schemas, and retrieve records programmatically. All responses are JSON. Real-time progress uses Server-Sent Events (SSE).

Quick Start

Integrate Entity Enricher in three steps:

1

Get Schema

GET /api/schema/saved

List saved schemas or generate one from sample data

2

Enrich

POST /api/single/enrich/stream

Start enrichment, get a job ID for SSE streaming

3

Get Result

GET /api/records/{id}

Retrieve the full enrichment record with structured output

Authentication

All API endpoints (except login/register) require authentication. Use the X-API-Key header with an organization access key:

curl -H "X-API-Key: ent_your_key_here" \
     https://your-instance.example.com/api/enrichment/options

Create API keys from the API Keys page or via POST /api/auth/api-keys. See the API Keys guide for details on key types and permissions.

Key Endpoints

Enrichment

MethodEndpointDescription
GET/api/enrichment/optionsAvailable models, languages, and strategies
POST/api/single/enrich/streamStart single entity enrichment (returns job_id for SSE)
POST/api/single/enrich/syncBlocking single enrichment for non-SSE clients (Make.com, curl)
POST/api/enrichment/batch/startStart batch enrichment for multiple entities
POST/api/enrichment/batch/fetchFetch entities from an external URL

Job Management

MethodEndpointDescription
GET/api/llm/stream/{job_id}SSE stream for any LLM job (enrichment, schema, fusion)
POST/api/llm/cancel/{job_id}Cancel a running or paused job
POST/api/llm/continue/{job_id}Resume a paused job (e.g., after classification mismatch)

Schemas

MethodEndpointDescription
GET/api/schema/savedList all saved schemas
POST/api/schema/savedCreate a new schema
POST/api/schema/generate/streamGenerate schema from sample data (SSE)
POST/api/schema/saved/{id}/prompt/streamAI-edit schema with natural language (SSE)
POST/api/schema/analyze-sampleAnalyze sample JSON for ambiguous property names — those admitting several readings in the context of their parent, or none — and for related items mixing entity facts with per-parent facts (stateless report, suggested renames)
POST/api/schema/saved/{id}/analyzeRun the ambiguity and identity-scoping checks on a saved schema and write their annotations (a rewritten description per ambiguous name)
POST/api/schema/scoping-splitApply one identity-scoping split to a sample set — the related entity's own facts move into their own subobject (deterministic, free, nothing saved)
DELETE/api/schema/saved/{id}/enrichment-dataPurge a schema's enrichment data — records and entity state — keeping the schema (owner+)

Records & Fusion

MethodEndpointDescription
GET/api/recordsList records with pagination and filtering
GET/api/records/{id}Get full record detail with structured output
POST/api/records/batch-deleteDelete multiple records (max 100)
POST/api/fusion/mergeMerge results from multiple models

Attachments

MethodEndpointDescription
POST/api/attachmentsUpload one or more files (multipart/form-data)
POST/api/attachments/base64Upload one file via JSON base64 (for non-multipart clients)
GET/api/attachments/{id}/downloadDownload the original file bytes
DELETE/api/attachments/{id}Delete an attachment (post-enrichment cleanup)

Schema Publishing & Samples

MethodEndpointDescription
POST/api/schema/saved/{id}/publishPublish a linked schema’s working copy as the contract enrichment and its databases run against. Nothing structural takes effect until this runs
POST/api/schema/sample/generate/streamGenerate 1..N sample JSON objects of one entity type (returns job_id for SSE)

Database Sync

MethodEndpointDescription
GET/api/databasesList the organization’s database registrations, with pending delta counts
POST/api/databasesRegister a database on a schema
GET/api/databases/{id}/snapshotDownload the full state as a .sql snapshot — bootstrap from zero
GET/api/databases/{id}/changesFetch the next FIFO window of deltas; claim them to lease for acknowledged delivery
POST/api/databases/{id}/ackAcknowledge applied deltas up to an id — releases the lease
POST/api/databases/{id}/clear-ackedPurge delivered and acknowledged deltas

Semantic Concepts

MethodEndpointDescription
GET/api/semantic-conceptsBrowse the concept vocabulary, filtered by type and scored against a reference concept
GET/api/semantic-concepts/typesList concept types with their counts and embedding models
POST/api/semantic-concepts/probeDry-run the resolution ladder for a text — what would it match, and how closely
GET/api/semantic-concepts/duplicatesConcept pairs sitting just below the merge threshold
POST/api/semantic-concepts/importBatch-resolve a CSV of identity texts (minting requires owner)
GET/api/semantic-concepts/exportExport the vocabulary as CSV
POST/api/semantic-concepts/delete-impactWhat deleting concepts would affect — usage counts and resync cost
GET/api/semantic-concepts/migration/statusState of the embedding-model migration, if one is running

Benchmarks & Billing

MethodEndpointDescription
GET/api/benchmarksList benchmark scenarios
POST/api/benchmarks/{id}/runRun a scenario across models — each result is scored automatically
POST/api/benchmarks/{id}/referenceSave and verify the gold reference a scenario is scored against
GET/api/billing/balanceCurrent credit balance
GET/api/billing/transactionsCredit transaction history, including embedding spend
GET/api/billing/plansAvailable plans and their limits

SSE Streaming

Enrichment, schema generation, and fusion operations use Server-Sent Events for real-time progress. Start a job, get a job_id, then connect to the SSE stream:

SSE Event Flow

data: {"type":"model_started","model":"anthropic::claude-sonnet-4-5"}
data: {"type":"expertise_completed","expertise_key":"financial","partial_result":{...}}
data: {"type":"model_completed","success":true,"result":{...},"record_id":"uuid"}
data: {"type":"completed"}

Key Event Types

EventDescription
model_startedModel processing begins
expertise_completedOne expertise domain finished (with partial results)
model_completedModel finished with result, record_id, and cost
fusion_started / fusion_completedMulti-model fusion lifecycle events
entity_started / entity_completedBatch-specific per-entity events (include entity_index)
completedTerminal event - close the connection
errorJob-level error occurred

Python Example

A complete workflow that lists schemas, starts enrichment, streams results, and retrieves the final record:

import httpx
import json

BASE = "https://your-instance.example.com"
KEY = "ent_your_api_key"
HEADERS = {"X-API-Key": KEY, "Content-Type": "application/json"}

# 1. List saved schemas
schemas = httpx.get(f"{BASE}/api/schema/saved", headers=HEADERS).json()
schema_id = schemas["schemas"][0]["id"]

# 2. Start enrichment
resp = httpx.post(f"{BASE}/api/single/enrich/stream", headers=HEADERS, json={
    "entity_data": {"name": "Moderna Inc", "country": "US"},
    "schema_id": schema_id,
    "models": ["anthropic::claude-sonnet-4-5-20250514"],
    "strategy": "multi_expertise",
})
job_id = resp.json()["job_id"]

# 3. Stream SSE events
record_id = None
with httpx.stream("GET", f"{BASE}/api/llm/stream/{job_id}", headers=HEADERS) as stream:
    for line in stream.iter_lines():
        if not line.startswith("data: "):
            continue
        event = json.loads(line[6:])

        if event["type"] == "model_completed" and event.get("record_id"):
            record_id = event["record_id"]
        elif event["type"] == "completed":
            break

# 4. Retrieve the enrichment record
if record_id:
    record = httpx.get(f"{BASE}/api/records/{record_id}", headers=HEADERS).json()
    print(json.dumps(record["structured_output"], indent=2))

curl Example

Start a batch enrichment with two models and stream the results:

# Start batch enrichment
JOB_ID=$(curl -s -X POST \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  "$BASE/api/enrichment/batch/start" \
  -d '{
    "entities": [
      {"name": "Pfizer Inc", "country": "US"},
      {"name": "Roche", "country": "CH"}
    ],
    "schema_id": "your-schema-uuid",
    "models": ["anthropic::claude-sonnet-4-5-20250514", "openai::gpt-4o"],
    "strategy": "multi_expertise",
    "arbitration_model": "anthropic::claude-sonnet-4-5-20250514"
  }' | jq -r '.job_id')

# Stream events
curl -N -H "X-API-Key: $KEY" "$BASE/api/llm/stream/$JOB_ID"

# List resulting records
curl -s -H "X-API-Key: $KEY" \
  "$BASE/api/records?type=enrichment&page_size=10" | jq '.records'

Error Handling

StatusMeaningExample
200SuccessRequest completed
400Bad requestInvalid model key or missing field
401UnauthorizedMissing or invalid API key
402Payment requiredPlan limit or credit balance — quota exhausted, too many models or languages, a feature not in your plan. The body carries a machine-readable code alongside detail.
403ForbiddenInsufficient role for this endpoint
404Not foundRecord, schema, or job not found
500Server errorInternal failure

Error responses include a detail field with a human-readable error message. Plan and billing failures (402) additionally carry a structured body with a stable codeprompt_limit_reached, insufficient_credits, model_limit_exceeded, benchmarks_not_in_plan — plus the relevant limit and usage numbers, so a client can branch on the cause instead of parsing prose. SSE streams emit an error event type before the terminal completed event if something fails mid-stream.

Model Composite Keys

Models are identified by composite keys in the format provider_name::model_name. Use GET /api/enrichment/options to list available models and their keys.

The model parameter is optional on enrichment, schema generation, and sample generation: omit it (or pass the literal "auto") and the server picks your organization's default model — the pinned per-task default if one is set in Settings, otherwise the model with the best overall score from your scoring-source benchmarks. The options response's default_models field shows what auto currently resolves to, and a model_auto_selected SSE event reports the pick on every job. Auto always resolves to a single model (it never triggers fusion); for reproducible pipelines, keep passing explicit models.

Request options constrain the auto pick: with enable_web_search: true only web-search-capable models are considered (the options response's default_models_web_search field previews that pick), and binary attachments require a model that can read them (PDF, vision, audio). When no eligible model satisfies the constraints the request fails with HTTP 400 no_capable_default_model instead of silently dropping the option.

Anthropic
anthropic::claude-sonnet-4-5-20250514
OpenAI
openai::gpt-4o
Google
google::gemini-2.5-pro
DeepSeek
deepseek::deepseek-chat

Interactive API Documentation

The application includes interactive API documentation with request/response examples. Requires admin authentication to access:

Next Steps