Skip to content

API integration

This page explains how to integrate an external backend, internal search UI, or RAG service with the SkeinRank governance API.

The recommended production pattern is binding-aware:

application search scope → binding_id → SkeinRank runtime API → existing search/RAG stack

A binding is the runtime context that tells SkeinRank which profile, index, fields, discriminator, and runtime snapshot should be used for a query.

Use the console first

Before integrating an application, use the governance console to create a profile, create a binding, run enrichment, audit the snapshot, and verify the behavior in Search Playground.

1. Choose scopeYour app decides which search area the user is in.
2. Resolve bindingMap that scope to a saved binding_id.
3. Plan or searchCall /v1/query/plan or /v1/search.
4. Render signalsUse canonical query, aliases, snapshot, and hits.
5. Audit changesUse snapshots and jobs to explain runtime behavior.

For the local Docker beta stack, the API listens on:

Terminal window
export SKEINRANK_API_URL="http://127.0.0.1:8010"

The governance console uses the same API through VITE_SKEINRANK_GOVERNANCE_API_URL.

When auth is enabled, API calls require a bearer token:

Authorization: Bearer <token>

For local testing, exchange the bootstrap admin credentials for a short-lived auth token:

Terminal window
curl -s -X POST "$SKEINRANK_API_URL/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"change-me-local-only"}'

Then export the returned access_token:

Terminal window
export SKEINRANK_TOKEN="<copy access_token here>"

Check the current user:

Terminal window
curl -s "$SKEINRANK_API_URL/v1/auth/me" \
-H "Authorization: Bearer $SKEINRANK_TOKEN"

For application integrations, prefer a service account token created from the API Access page or through the service-account token endpoint:

POST /v1/auth/service-accounts/{account_name}/tokens

Personal tokens are useful for developer testing:

POST /v1/auth/api-tokens

Token handling

Token create responses return the plaintext token once. Store it in your application secret manager and do not commit it to source control.

The external application should know which search context the user selected. For example:

Infra incidents → binding_id 42
Product docs → binding_id 51
Legal docs → binding_id 77

You can list saved Elasticsearch bindings:

Terminal window
curl -s "$SKEINRANK_API_URL/v1/governance/elasticsearch/bindings" \
-H "Authorization: Bearer $SKEINRANK_TOKEN"

Optionally filter by profile:

Terminal window
curl -s "$SKEINRANK_API_URL/v1/governance/elasticsearch/bindings?profile_name=infra_incidents" \
-H "Authorization: Bearer $SKEINRANK_TOKEN"

A binding response includes fields such as id, profile_name, index_name, text_fields, target_field, filter_field, filter_value, snapshot_status, and last_successful_snapshot_version.

Use query planning when you want to inspect how SkeinRank understands a query without executing Elasticsearch search. This is the API equivalent of the Search Playground preview action.

POST /v1/query/plan
Terminal window
curl -s -X POST "$SKEINRANK_API_URL/v1/query/plan" \
-H "Authorization: Bearer $SKEINRANK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"binding_id": 42,
"query": "k8s pg timeout",
"size": 10,
"canonical_boost": 3.0,
"include_evidence": true
}'

Important response fields:

FieldMeaning
canonical_queryThe query after alias replacement, for example kubernetes postgresql timeout.
matched_aliasesAliases recognized in the input query.
canonical_valuesCanonical values that can be used as retrieval signals.
snapshot_versionThe runtime snapshot used for the binding, when available.
elasticsearchThe generated Elasticsearch DSL preview.
warningsHelpful messages such as missing aliases or profile-only fallback.

Use search when you want SkeinRank to execute the generated Elasticsearch query through the configured binding.

POST /v1/search
Terminal window
curl -s -X POST "$SKEINRANK_API_URL/v1/search" \
-H "Authorization: Bearer $SKEINRANK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"binding_id": 42,
"query": "k8s pg timeout",
"size": 10,
"canonical_boost": 3.0,
"include_source": true,
"source_fields": ["title", "body", "skeinrank.attributes"],
"include_evidence": true
}'

A search response includes both the query understanding payload and Elasticsearch hits:

{
"binding_id": 42,
"query": "k8s pg timeout",
"canonical_query": "kubernetes postgresql timeout",
"matched_aliases": ["k8s", "pg"],
"canonical_values": ["kubernetes", "postgresql"],
"snapshot_version": "infra_incidents@2026-05-runtime",
"hits": [
{
"id": "doc-001",
"index": "company_docs",
"score": 12.4,
"source": {
"title": "Kubernetes timeout during PostgreSQL failover"
},
"skeinrank": {
"canonical_values": ["kubernetes", "postgresql"]
}
}
],
"warnings": []
}

Use canonicalization when your application wants terminology normalization but not Elasticsearch execution.

POST /v1/text/canonicalize
Terminal window
curl -s -X POST "$SKEINRANK_API_URL/v1/text/canonicalize" \
-H "Authorization: Bearer $SKEINRANK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"binding_id": 42,
"text": "Investigate k8s pg timeout after rollout",
"mode": "replace",
"include_evidence": true
}'

Supported modes are:

ModeUse case
annotateReturn matches and evidence without changing the text.
replaceReturn canonicalized text such as kubernetes postgresql timeout.
attributesReturn extracted canonical values and slots for downstream processing.

When your product has an “All docs” or “All workspaces” search scope, call multi-search with explicit bindings.

POST /v1/search/multi
Terminal window
curl -s -X POST "$SKEINRANK_API_URL/v1/search/multi" \
-H "Authorization: Bearer $SKEINRANK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"binding_ids": [42, 51, 77],
"query": "phoenix timeout",
"size": 10,
"per_binding_size": 5,
"canonical_boost": 3.0,
"include_source": true
}'

This keeps each binding isolated while still returning merged hits. The response reports succeeded_bindings, failed_bindings, per-binding results, and merged hits.

A backend should usually map application context to a binding rather than asking users to type binding IDs.

const scopeToBinding: Record<string, number> = {
infra_incidents: 42,
product_docs: 51,
legal_docs: 77,
};
export async function runSkeinRankSearch(scope: string, query: string) {
const bindingId = scopeToBinding[scope];
if (!bindingId) {
throw new Error(`Unknown search scope: ${scope}`);
}
const response = await fetch(`${process.env.SKEINRANK_API_URL}/v1/search`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SKEINRANK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
binding_id: bindingId,
query,
size: 10,
canonical_boost: 3,
include_source: true,
}),
});
if (!response.ok) {
throw new Error(`SkeinRank search failed: ${response.status}`);
}
return response.json();
}

A search UI does not need to expose every internal field. Useful product-level signals are:

  • canonical_query — show how the query was normalized;
  • matched_aliases and replacements — explain why it changed;
  • snapshot_version — audit which runtime version was used;
  • warnings — surface configuration issues to admins;
  • hits — render search results normally.

For operator or admin UIs, link back to the SkeinRank console:

Search issue → open binding in Integrations → audit snapshot → inspect jobs
StatusTypical reasonAction
401Missing or invalid bearer token.Create or refresh a token.
403The token owner role is not allowed to call the endpoint.Use a service account with the right role.
422Required fields are missing, such as binding_id, query, or text fields.Validate the request body before sending.
503Elasticsearch is not configured or cannot be reached.Check the integration configuration and service health.
  • Do not use profile_name alone for production search if you already have bindings.
  • Do not hard-code alias rules inside the application backend.
  • Do not bypass snapshots when explaining runtime search behavior.
  • Do not expose admin tokens to browsers; use an application backend or service account.
  • Do not treat the Search Playground as the integration surface. It mirrors the runtime APIs but is not the API itself.

When the governance API is running locally, FastAPI also exposes interactive documentation:

http://127.0.0.1:8010/docs
http://127.0.0.1:8010/redoc

Use this page for the product-level integration pattern, and use the local OpenAPI UI for exact request/response schemas while the beta API is still evolving.