---
title: "Chained multi-hop search"
method: POST
path: "/v1/search/multi-hop"
tags: ["Search"]
---

# Chained multi-hop search

`POST /v1/search/multi-hop`

## Request

- Base URL: `https://brain.inite.ai`
- URL: `https://brain.inite.ai/v1/search/multi-hop`
- Auth: HTTP bearer

A planner LLM decomposes the query into at most `maxHops` anchored sub-queries; each later hop is scoped to the running entity set, so the engine never spends compute on candidates already disqualified. Answers questions that join evidence across turns or entities. `supportingFactIds` is the evidence chain (HotpotQA-style) — the caller can audit exactly which facts drove the answer. `synthesize: true` adds a grounded answer with citations alongside the per-hop trace. Fans out to the shared embedding / LLM budget, so it sits in the per-credential `expensive` throttle bucket — 10 requests/min, not the 120/min default. Source: src/multi-hop/multi-hop.controller.ts.

Required scope: `brain:read`.

## Request body

- MultiHopRequest
  - `asOf` string
  - `confidenceFloor` number
  - `disableLangFilter` boolean
  - `entityIds` string[]
  - `entityTypes` string[]
  - `includeContested` boolean
  - `includeRetracted` boolean
  - `includeStale` boolean
  - `limit` number
  - `maxHops` integer
  - `minConfidence` number
  - `outputShape` 'full' | 'compact' | 'ids'
  - `predicates` string[]
  - `query` string, required
  - `queryLang` string
  - `requireProvenance` boolean
  - `searchMode` 'vector' | 'lexical' | 'hybrid'
  - `synthesisGuardrails` 'strict' | 'lenient' | 'off' | 'answer'
  - `synthesisModel` string
  - `synthesize` boolean
  - `tokenBudget` number
  - `userId` string

## Response `201`

The hop trace and the final entity set.

- MultiHopResponse
  - `finalEntityIds` string[], required
  - `finalHits` SearchHit[], required
    - `canonicalName` string, required
    - `entityId` string, required
    - `entityType` string, required
    - `externalRefs` object, required
    - `facts` SearchFact[], required
      - `breakdown` ScoreBreakdown
      - `confidence` number, required
      - `date` string
      - `expectedUntil` string
      - `factId` string, required
      - `highlight` string
      - `mentionedAt` string
      - `object` string, required
      - `predicate` string, required
      - `predicateAlias` string
      - `scene` string
      - `score` number, required
      - `sourceKey` string
      - `status` string, required
      - `validFrom` string, required
      - `validUntil` string
    - `relations` object[]
      - `direction` 'out' | 'in'
      - `edgeId` string
      - `kind` string, required
      - `peer` string, required
      - `peerId` string
      - `peerType` string, required
      - `validFrom` string
      - `validUntil` string
    - `score` number, required
  - `hops` HopOutcome[], required
    - `hits` SearchHit[], required
      - `canonicalName` string, required
      - `entityId` string, required
      - `entityType` string, required
      - `externalRefs` object, required
      - `facts` SearchFact[], required
        - `breakdown` ScoreBreakdown
        - `confidence` number, required
        - `date` string
        - `expectedUntil` string
        - `factId` string, required
        - `highlight` string
        - `mentionedAt` string
        - `object` string, required
        - `predicate` string, required
        - `predicateAlias` string
        - `scene` string
        - `score` number, required
        - `sourceKey` string
        - `status` string, required
        - `validFrom` string, required
        - `validUntil` string
      - `relations` object[]
        - `direction` 'out' | 'in'
        - `edgeId` string
        - `kind` string, required
        - `peer` string, required
        - `peerId` string
        - `peerType` string, required
        - `validFrom` string
        - `validUntil` string
      - `score` number, required
    - `hop` HopPlan, required
      - `asOf` string, nullable
      - `combination` 'seed' | 'subset_of_previous' | 'intersect' | 'union', required
      - `predicates` string[], nullable
      - `rationale` string, nullable
      - `subQuery` string, required
    - `hopEntityIds` string[], required
    - `runningEntityIds` string[], required
    - `supportingFactIds` string[], required
  - `isMultiHop` boolean, required
  - `supportingFactIds` string[], required
  - `synthesis` object
    - `answer` string, nullable, required
    - `citations` Citation[], required
      - `canonicalName` string, required
      - `entityId` string, required
      - `factId` string, required
      - `object` string, required
      - `predicate` string, required
      - `slot` string, required
      - `sourceKey` string
      - `validFrom` string
    - `reason` 'no_results' | 'no_grounded_evidence' | 'low_coverage' | 'evidence_capability_unmet' | 'ungrounded_evidence' | 'verifier_failed' | 'verifier_partial' | 'generator_error' | 'verifier_error'
    - `tokenUsage` TokenUsage
      - `completionTokens` number, required
      - `promptTokens` number, required

## Other responses

- `400`: Validation failed.
- `401`: Missing or unknown bearer key.
- `403`: The key lacks the required scope.
- `429`: Per-credential throttle exceeded.

---

[API](https://skmtc.dev/inite/apis/inite-brain-platform-api.md) · [All operations](https://skmtc.dev/inite/apis/inite-brain-platform-api/llms.txt) · [OpenAPI document](https://skmtc.dev/inite/apis/inite-brain-platform-api/revisions/c7c3eb5e304b?raw)
