> For the complete documentation index, see [llms.txt](https://docs.otari.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.otari.ai/otari/for-integrators/api-reference/routing.md).

# Routing

## List Automatic Fallbacks

> The models the caller's organization sent requests to in the last 30 days, and the fallback each gets.\
> \
> A request that sends a model's catalog ID moves to the model's next offering\
> when one fails, with no policy. Each model lists its offerings in the order\
> such a request tries them, priced for this organization, with who runs the\
> built-in tools on each, beside its traffic: how many requests a backup served,\
> and how many named one offering and so had no fallback. The traffic is the\
> workspaces the caller may see in their active organization, by the rule the\
> organization's usage reads use.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"AutomaticFallbacksResponse":{"description":"The automatic fallbacks the caller's organization used.","properties":{"models":{"description":"Most requested first.","items":{"$ref":"#/components/schemas/AutomaticFallbackPublic"},"title":"Models","type":"array"},"window_days":{"description":"How many days of traffic the counts cover.","title":"Window Days","type":"integer"}},"required":["window_days","models"],"title":"AutomaticFallbacksResponse","type":"object"},"AutomaticFallbackPublic":{"description":"One model the caller's organization used in the window, and the fallback a catalog ID gives it.","properties":{"fell_back":{"description":"Of `requests`, the successful ones a later offering served.","title":"Fell Back","type":"integer"},"id":{"description":"The catalog ID a caller sends to get the fallback, e.g. `anthropic/claude-sonnet-5`.","title":"Id","type":"string"},"name":{"title":"Name","type":"string"},"offerings":{"description":"What a request sent by catalog ID tries, first first. One entry means no backup.","items":{"$ref":"#/components/schemas/FallbackOfferingPublic"},"title":"Offerings","type":"array"},"pinned":{"description":"Of `requests`, those that named an offering or a policy rather than the catalog ID, and so got no automatic fallback.","title":"Pinned","type":"integer"},"pinned_provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The instance most pinned requests reached.","title":"Pinned Provider"},"requests":{"description":"Requests served in the window, each counted once however many attempts.","title":"Requests","type":"integer"}},"required":["id","name","offerings","requests","fell_back","pinned","pinned_provider"],"title":"AutomaticFallbackPublic","type":"object"},"FallbackOfferingPublic":{"description":"One offering a catalog ID tries, and who runs the built-in tools on it.","properties":{"otari_tools":{"description":"Built-in tools Otari runs in this provider's place, for that caller.","items":{"type":"string"},"title":"Otari Tools","type":"array"},"own_tools":{"description":"Built-in tools this provider runs itself, for a caller that declares them in the provider's own words and leaves the choice of executor to the deployment.","items":{"type":"string"},"title":"Own Tools","type":"array"},"provider":{"description":"The provider instance the selector names.","title":"Provider","type":"string"},"provider_type":{"description":"The any-llm implementation behind the instance.","title":"Provider Type","type":"string"},"selector":{"description":"The offering, in `instance:model` form.","title":"Selector","type":"string"}},"required":["selector","provider","provider_type","own_tools","otari_tools"],"title":"FallbackOfferingPublic","type":"object"}}},"paths":{"/api/v1/organizations/me/automatic-fallbacks":{"get":{"description":"The models the caller's organization sent requests to in the last 30 days, and the fallback each gets.\n\nA request that sends a model's catalog ID moves to the model's next offering\nwhen one fails, with no policy. Each model lists its offerings in the order\nsuch a request tries them, priced for this organization, with who runs the\nbuilt-in tools on each, beside its traffic: how many requests a backup served,\nand how many named one offering and so had no fallback. The traffic is the\nworkspaces the caller may see in their active organization, by the rule the\norganization's usage reads use.","operationId":"routing-list_automatic_fallbacks","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomaticFallbacksResponse"}}},"description":"Successful Response"}},"summary":"List Automatic Fallbacks","tags":["routing"]}}}}
```

## List Visible Routing Policies

> List the routing policies in force in the workspaces this caller may see.\
> \
> Stored policies from the caller's visible workspaces plus the config-file\
> policies, which are deployment-wide and resolve in every workspace. The\
> response is the shape \`\`GET /api/v1/routing/policies\`\` answers, narrowed to the\
> caller's own organization, and narrowed again to one workspace when\
> \`\`workspace\_id\`\` names one.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"PolicyResponse":{"description":"A routing policy and where it is defined.","properties":{"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"is_dynamic":{"default":false,"title":"Is Dynamic","type":"boolean"},"name":{"title":"Name","type":"string"},"source":{"title":"Source","type":"string"},"spec":{"additionalProperties":true,"title":"Spec","type":"object"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"title":"Workspace Id"}},"required":["name","spec","source"],"title":"PolicyResponse","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/organizations/me/routing-policies":{"get":{"description":"List the routing policies in force in the workspaces this caller may see.\n\nStored policies from the caller's visible workspaces plus the config-file\npolicies, which are deployment-wide and resolve in every workspace. The\nresponse is the shape ``GET /api/v1/routing/policies`` answers, narrowed to the\ncaller's own organization, and narrowed again to one workspace when\n``workspace_id`` names one.","operationId":"routing-list_visible_routing_policies","parameters":[{"description":"Maximum entries to return, stored and config-file together.","in":"query","name":"limit","required":false,"schema":{"default":1000,"description":"Maximum entries to return, stored and config-file together.","maximum":1000,"minimum":1,"title":"Limit","type":"integer"}},{"description":"Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit for every workspace this caller may see.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Only stored entries in this workspace. Config-file entries are always included, being deployment-wide. Omit for every workspace this caller may see.","title":"Workspace Id"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PolicyResponse"},"title":"Response Routing-List Visible Routing Policies","type":"array"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"List Visible Routing Policies","tags":["routing"]}}}}
```

## Set Organization Routing Policy

> Create or update a stored policy in one of the organization's workspaces.\
> \
> Organization owners and admins only. \`\`workspace\_id\`\` is required and must\
> name a workspace of the caller's own organization; \`\`user\_id\`\` is not\
> accepted here.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"PolicyRequest":{"description":"Request to create or update a routing policy.","properties":{"name":{"description":"Model name callers send, e.g. 'fast'.","title":"Name","type":"string"},"rename_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Current name of the policy to rename, in the same scope, meaning the same workspace and the same user. A rename never moves a policy between them. The stored row keeps its id and created_at and takes `name` and `spec`. Sending it asserts that policy exists, so a name with no stored row is a 404 rather than a create, even when it equals `name`. Omit to create or update the policy named `name`. Renaming changes what callers must send as `model`; usage already recorded keeps the old name.","title":"Rename From"},"spec":{"additionalProperties":true,"description":"The policy body: select (with exactly one `default` entry, last), optional on_failure and guardrails. Same schema as a `routing.policies` entry in config.yml, and closed to unknown keys, so a typo is a 400 rather than a silently ignored setting.","title":"Spec","type":"object"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"User this policy belongs to. Omit for a policy every caller in the workspace sees. A user-scoped policy resolves only for that user and shadows the workspace-wide one of the same name.","title":"User Id"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Workspace this policy belongs to. Omit for the deployment's default workspace. The policy resolves only for requests in that workspace, so two workspaces can each define their own 'fast'.","title":"Workspace Id"}},"required":["name","spec"],"title":"PolicyRequest","type":"object"},"PolicyResponse":{"description":"A routing policy and where it is defined.","properties":{"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"is_dynamic":{"default":false,"title":"Is Dynamic","type":"boolean"},"name":{"title":"Name","type":"string"},"source":{"title":"Source","type":"string"},"spec":{"additionalProperties":true,"title":"Spec","type":"object"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"title":"Workspace Id"}},"required":["name","spec","source"],"title":"PolicyResponse","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/organizations/me/routing-policies":{"post":{"description":"Create or update a stored policy in one of the organization's workspaces.\n\nOrganization owners and admins only. ``workspace_id`` is required and must\nname a workspace of the caller's own organization; ``user_id`` is not\naccepted here.","operationId":"routing-set_organization_routing_policy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyResponse"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Set Organization Routing Policy","tags":["routing"]}}}}
```

## Delete Organization Routing Policy

> Delete a stored policy from one of the organization's workspaces. Owners and admins only.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/organizations/me/routing-policies/{name}":{"delete":{"description":"Delete a stored policy from one of the organization's workspaces. Owners and admins only.","operationId":"routing-delete_organization_routing_policy","parameters":[{"in":"path","name":"name","required":true,"schema":{"title":"Name","type":"string"}},{"description":"Delete the policy in this workspace of the caller's organization.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Delete the policy in this workspace of the caller's organization.","title":"Workspace Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Delete Organization Routing Policy","tags":["routing"]}}}}
```

## List Policies

> List every routing policy in force in your organization, from config.yml and from storage.\
> \
> Every scope at once, workspace-wide and user-scoped alike: this is the\
> master-key management view, not what any one caller resolves.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"PolicyResponse":{"description":"A routing policy and where it is defined.","properties":{"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"is_dynamic":{"default":false,"title":"Is Dynamic","type":"boolean"},"name":{"title":"Name","type":"string"},"source":{"title":"Source","type":"string"},"spec":{"additionalProperties":true,"title":"Spec","type":"object"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"title":"Workspace Id"}},"required":["name","spec","source"],"title":"PolicyResponse","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/routing/policies":{"get":{"description":"List every routing policy in force in your organization, from config.yml and from storage.\n\nEvery scope at once, workspace-wide and user-scoped alike: this is the\nmaster-key management view, not what any one caller resolves.","operationId":"routing-list_policies","parameters":[{"description":"Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Only stored policies in this workspace. Config-file policies are always included, being deployment-wide. Omit to list the stored policies of every workspace in your organization.","title":"Workspace Id"}}],"responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PolicyResponse"},"title":"Response Routing-List Policies","type":"array"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"List Policies","tags":["routing"]}}}}
```

## Set Policy

> Create or update a stored policy in one workspace, optionally for one user.\
> \
> Omitting \`\`workspace\_id\`\` means the deployment's default workspace, which is\
> where an operator acting deployment-wide writes.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"PolicyRequest":{"description":"Request to create or update a routing policy.","properties":{"name":{"description":"Model name callers send, e.g. 'fast'.","title":"Name","type":"string"},"rename_from":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Current name of the policy to rename, in the same scope, meaning the same workspace and the same user. A rename never moves a policy between them. The stored row keeps its id and created_at and takes `name` and `spec`. Sending it asserts that policy exists, so a name with no stored row is a 404 rather than a create, even when it equals `name`. Omit to create or update the policy named `name`. Renaming changes what callers must send as `model`; usage already recorded keeps the old name.","title":"Rename From"},"spec":{"additionalProperties":true,"description":"The policy body: select (with exactly one `default` entry, last), optional on_failure and guardrails. Same schema as a `routing.policies` entry in config.yml, and closed to unknown keys, so a typo is a 400 rather than a silently ignored setting.","title":"Spec","type":"object"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"User this policy belongs to. Omit for a policy every caller in the workspace sees. A user-scoped policy resolves only for that user and shadows the workspace-wide one of the same name.","title":"User Id"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Workspace this policy belongs to. Omit for the deployment's default workspace. The policy resolves only for requests in that workspace, so two workspaces can each define their own 'fast'.","title":"Workspace Id"}},"required":["name","spec"],"title":"PolicyRequest","type":"object"},"PolicyResponse":{"description":"A routing policy and where it is defined.","properties":{"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"is_dynamic":{"default":false,"title":"Is Dynamic","type":"boolean"},"name":{"title":"Name","type":"string"},"source":{"title":"Source","type":"string"},"spec":{"additionalProperties":true,"title":"Spec","type":"object"},"updated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Updated At"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"title":"Workspace Id"}},"required":["name","spec","source"],"title":"PolicyResponse","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/routing/policies":{"post":{"description":"Create or update a stored policy in one workspace, optionally for one user.\n\nOmitting ``workspace_id`` means the deployment's default workspace, which is\nwhere an operator acting deployment-wide writes.","operationId":"routing-set_policy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolicyResponse"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Set Policy","tags":["routing"]}}}}
```

## Explain Policy

> Compile a policy and return the plan, without dispatching anything.\
> \
> Operator-gated, and deliberately so: the response enumerates the policy's\
> targets, which is exactly the information a policy exists to keep off the wire.\
> It is a management surface, not a caller-facing one.\
> \
> Accepts an unsaved \`\`spec\`\` as well as a saved \`\`name\`\`, so a form can validate\
> what the operator is about to save. The response includes dropped candidates\
> with reasons, which is the part that catches a "failover" policy that has\
> quietly compiled down to a single attempt.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"ExplainRequest":{"description":"Ask what a policy would do, without dispatching anything.\n\nEither name a stored/configured policy (``name``) or pass a draft ``spec`` that\nhas not been saved. The draft form is what makes authoring-time validation\npossible: the compiler filters candidates, so a chain can compile down to one\nattempt, and an author needs to see that before saving rather than during an\noutage.","properties":{"allowed_models":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"description":"Simulate an API key's allow-list. Omit for unrestricted.","title":"Allowed Models"},"budget_remaining_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Simulated budget remaining, USD.","title":"Budget Remaining Usd"},"budget_used_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Simulated budget usage percentage.","title":"Budget Used Pct"},"key_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Evaluate conditions as this API key id.","title":"Key Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"An existing policy to explain.","title":"Name"},"spec":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"description":"An unsaved policy body to explain.","title":"Spec"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Evaluate conditions as this user.","title":"User Id"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Resolve `name` and the policy's candidate selectors in this workspace. Omit for the deployment's default workspace.","title":"Workspace Id"}},"title":"ExplainRequest","type":"object"},"ExplainResponse":{"description":"The plan a policy compiles to for the given inputs.","properties":{"candidates":{"items":{"$ref":"#/components/schemas/CandidateResponse"},"title":"Candidates","type":"array"},"dropped":{"items":{"$ref":"#/components/schemas/DroppedResponse"},"title":"Dropped","type":"array"},"guardrails":{"items":{"additionalProperties":true,"type":"object"},"title":"Guardrails","type":"array"},"is_dynamic":{"title":"Is Dynamic","type":"boolean"},"name":{"title":"Name","type":"string"},"router_backend":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Router Backend"},"router_candidates":{"items":{"type":"string"},"title":"Router Candidates","type":"array"},"router_weights":{"additionalProperties":{"type":"number"},"description":"For a weighted policy, the percentage of traffic each candidate receives, normalized over the candidates this caller may use. Empty for every other policy, and for a weighted policy whose whole split this caller may not use: a split over no candidate is not a split, and each filtered candidate is named in `dropped` instead. A weighted split needs no request state, so unlike a learned router's ranking it is knowable here: the plan above is the real ordering by share, not the decline path.","title":"Router Weights","type":"object"},"selection_reason":{"title":"Selection Reason","type":"string"}},"required":["name","selection_reason","is_dynamic","candidates","dropped","guardrails"],"title":"ExplainResponse","type":"object"},"CandidateResponse":{"description":"One candidate in a compiled plan.","properties":{"dispatch_model":{"title":"Dispatch Model","type":"string"},"instance":{"title":"Instance","type":"string"},"model":{"title":"Model","type":"string"},"position":{"title":"Position","type":"integer"},"selection_reason":{"title":"Selection Reason","type":"string"}},"required":["position","instance","model","selection_reason","dispatch_model"],"title":"CandidateResponse","type":"object"},"DroppedResponse":{"description":"A candidate that was filtered out, and why.","properties":{"detail":{"title":"Detail","type":"string"},"reason":{"title":"Reason","type":"string"},"selector":{"title":"Selector","type":"string"}},"required":["selector","reason","detail"],"title":"DroppedResponse","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/routing/policies/explain":{"post":{"description":"Compile a policy and return the plan, without dispatching anything.\n\nOperator-gated, and deliberately so: the response enumerates the policy's\ntargets, which is exactly the information a policy exists to keep off the wire.\nIt is a management surface, not a caller-facing one.\n\nAccepts an unsaved ``spec`` as well as a saved ``name``, so a form can validate\nwhat the operator is about to save. The response includes dropped candidates\nwith reasons, which is the part that catches a \"failover\" policy that has\nquietly compiled down to a single attempt.","operationId":"routing-explain_policy","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplainRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExplainResponse"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Explain Policy","tags":["routing"]}}}}
```

## Delete Policy

> Delete a stored policy in one scope.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/routing/policies/{name}":{"delete":{"description":"Delete a stored policy in one scope.","operationId":"routing-delete_policy","parameters":[{"in":"path","name":"name","required":true,"schema":{"title":"Name","type":"string"}},{"description":"Delete the policy scoped to this user. Omit to delete the workspace-wide one.","in":"query","name":"user_id","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Delete the policy scoped to this user. Omit to delete the workspace-wide one.","title":"User Id"}},{"description":"Delete the policy in this workspace. Omit for the deployment's default workspace.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Delete the policy in this workspace. Omit for the deployment's default workspace.","title":"Workspace Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Delete Policy","tags":["routing"]}}}}
```

## Rank Candidates

> Record scored examples: one routing-memory record each, plus an audit row.\
> \
> The routing-memory record is written before its audit row for each example,\
> because it is the load-bearing one (the router votes over it) and embedding it\
> can fail; writing the audit row only afterwards means a failed embedding never\
> leaves an orphan audit row.\
> \
> A failed embedding is a 502 that names the model, not a 500. Every example in\
> the batch is embedded, so this is the call an operator makes most often and the\
> one most likely to meet a misconfigured \`\`router\_embedding\_model\`\`.\
> \
> Score keys are stored canonically as \`\`instance:model\`\` (see\
> :func:\`\_validated\_scores\`), which is the form the router canonicalizes its\
> candidates to, so how a policy spells a candidate cannot decide whether it\
> matches.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"RankRequest":{"description":"Record how well each candidate did, for one or many prompts.\n\nA batch because of the arithmetic: a pool routes nothing until it holds\n``router_seed_count`` examples (20 by default) and the vote reads the ``k``\nnearest (5 by default), so a useful first teaching pass is dozens of examples\nacross the kinds of prompt you care about.","properties":{"user_id":{"description":"Whose routing memory these examples belong to.","title":"User Id","type":"string"},"workspace_id":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Which workspace's routing memory these examples belong to. Omit for the deployment's default workspace. Only requests billing to that workspace vote over them.","title":"Workspace Id"}},"required":["user_id","examples"],"title":"RankRequest","type":"object"},"RankResponse":{"properties":{"pools":{"items":{"$ref":"#/components/schemas/RecordedPool"},"title":"Pools","type":"array"},"recorded":{"title":"Recorded","type":"integer"},"seed_count":{"title":"Seed Count","type":"integer"}},"required":["recorded","seed_count","pools"],"title":"RankResponse","type":"object"},"RecordedPool":{"description":"How warm one pool is after the write.","properties":{"records":{"title":"Records","type":"integer"},"task_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Id"},"warm":{"title":"Warm","type":"boolean"}},"required":["task_id","records","warm"],"title":"RecordedPool","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/routing/preferences/rank":{"post":{"description":"Record scored examples: one routing-memory record each, plus an audit row.\n\nThe routing-memory record is written before its audit row for each example,\nbecause it is the load-bearing one (the router votes over it) and embedding it\ncan fail; writing the audit row only afterwards means a failed embedding never\nleaves an orphan audit row.\n\nA failed embedding is a 502 that names the model, not a 500. Every example in\nthe batch is embedded, so this is the call an operator makes most often and the\none most likely to meet a misconfigured ``router_embedding_model``.\n\nScore keys are stored canonically as ``instance:model`` (see\n:func:`_validated_scores`), which is the form the router canonicalizes its\ncandidates to, so how a policy spells a candidate cannot decide whether it\nmatches.","operationId":"routing-rank_candidates","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RankRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RankResponse"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Rank Candidates","tags":["routing"]}}}}
```

## Recommend Model For Agent

> Recommend the model a subagent about to start should run on.\
> \
> The harness sends the facts it holds at spawn time: its own ids for the\
> session and the spawning tool call, the subagent type, the task, the\
> parent's model and the model the caller asked for, if any. The recommender\
> this build binds picks one of the candidate models and the answer names it.\
> By default the deployment asks the decision model \`agent\_recommender\_model\`\
> names to choose among \`agent\_recommender\_candidates\` for Claude Code and\
> among the request's own \`candidates\` for pi; a bootstrap may bind a\
> recommender of its own, which the caller never configures. Where\
> the recommender reports them, the answer also carries a one-line reason\
> and its probability for each candidate.\
> \
> Authentication modes:\
> \- Master key: the \`\`user\`\` field is required and names who the decision is billed to.\
> \- API key: the decision is billed to the key's own user.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"AgentModelRecommendationRequest":{"additionalProperties":false,"description":"A coding agent about to start a subagent, asking which model it should run on.\n\nEvery field but ``user`` is a fact the harness already holds at spawn time.\nThe prompt is the task the subagent is given; it is read for the\nrecommendation and never stored or logged.","properties":{"agent_type":{"description":"The subagent type: a built-in such as `Explore` or `Plan`, or a custom agent's name.","maxLength":128,"minLength":1,"title":"Agent Type","type":"string"},"candidates":{"anyOf":[{"maxProperties":255,"minProperties":2,"patternProperties":{"^[^:\\s]+:\\S+$":{"anyOf":[{"maxLength":1024,"type":"string"},{"type":"null"}]}},"propertyNames":{"maxLength":256},"type":"object"},{"type":"null"}],"description":"The models the subagent may be sent to, as Otari model ids (`<provider>:<model>`), each with what it is for (or null when the name says enough). Required for `pi`, refused for `claude-code`.","title":"Candidates"},"description":{"default":"","description":"The caller's short description of the task.","maxLength":1024,"title":"Description","type":"string"},"harness":{"description":"The agent harness asking. It decides the candidates: `agent_recommender_candidates`, Claude Code's own aliases, for `claude-code`, and the request's own `candidates` for `pi`.","enum":["claude-code","pi"],"title":"Harness","type":"string"},"parent_model":{"description":"The model the parent conversation runs on, as the harness names it.","maxLength":256,"minLength":1,"title":"Parent Model","type":"string"},"prompt":{"description":"The task the subagent is given.","maxLength":65536,"minLength":1,"title":"Prompt","type":"string"},"requested_model":{"anyOf":[{"maxLength":256,"type":"string"},{"type":"null"}],"description":"The model the caller asked for, if any. Sent as a fact; the recommendation is the gateway's.","title":"Requested Model"},"session_id":{"description":"The harness's own id for the session the spawn happens in.","maxLength":256,"minLength":1,"title":"Session Id","type":"string"},"tool_use_id":{"description":"The harness's own id for the tool call that spawns the subagent.","maxLength":256,"minLength":1,"title":"Tool Use Id","type":"string"},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"User ID the decision is billed to when asking with the master key; not sent upstream.","title":"User"}},"required":["harness","session_id","tool_use_id","agent_type","prompt","parent_model"],"title":"AgentModelRecommendationRequest","type":"object"},"AgentModelRecommendation":{"description":"The model recommended for the subagent.","properties":{"model":{"description":"A model alias or id the harness can start the subagent on.","title":"Model","type":"string"},"probabilities":{"anyOf":[{"additionalProperties":{"type":"number"},"type":"object"},{"type":"null"}],"description":"The decision model's probability for each candidate, when it reports them.","title":"Probabilities"},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Why, in one short sentence the harness may show.","title":"Reason"}},"required":["model"],"title":"AgentModelRecommendation","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/routing/recommend":{"post":{"description":"Recommend the model a subagent about to start should run on.\n\nThe harness sends the facts it holds at spawn time: its own ids for the\nsession and the spawning tool call, the subagent type, the task, the\nparent's model and the model the caller asked for, if any. The recommender\nthis build binds picks one of the candidate models and the answer names it.\nBy default the deployment asks the decision model `agent_recommender_model`\nnames to choose among `agent_recommender_candidates` for Claude Code and\namong the request's own `candidates` for pi; a bootstrap may bind a\nrecommender of its own, which the caller never configures. Where\nthe recommender reports them, the answer also carries a one-line reason\nand its probability for each candidate.\n\nAuthentication modes:\n- Master key: the ``user`` field is required and names who the decision is billed to.\n- API key: the decision is billed to the key's own user.","operationId":"routing-recommend_model_for_agent","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentModelRecommendationRequest"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentModelRecommendation"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Recommend Model For Agent","tags":["routing"]}}}}
```

## Routing Memory Status

> Report how warm one user's routing memory is in one workspace, per pool.\
> \
> \`\`user\_id\`\` is required rather than optional because there is no aggregate\
> answer: warmth is per user, and a total across users would describe a pool\
> that no request ever votes over. The same holds across workspaces, which is\
> why \`\`workspace\_id\`\` narrows rather than aggregating; it merely defaults\
> instead of being required, because a single-workspace deployment has one\
> answer.

```json
{"openapi":"3.1.0","info":{"title":"otari","version":"0.33.0"},"security":[{"ApiKeyAuth":[]},{"XApiKeyAuth":[]}],"components":{"securitySchemes":{"ApiKeyAuth":{"description":"Enter your API key here (sent as Otari-Key header).","in":"header","name":"Otari-Key","type":"apiKey"},"XApiKeyAuth":{"description":"Anthropic-native clients send credentials here (no Bearer prefix).","in":"header","name":"x-api-key","type":"apiKey"}},"schemas":{"RouterStatus":{"description":"How warm this user's routing memory is, and what depends on it.\n\nRouting memory has no single warmth: it is a set of independent pools.\n``default_pool`` is what a request with no ``Otari-Router-Task`` header votes\nover (every record the user has in this workspace, labeled or not) and\n``tasks`` lists each partition, which only requests carrying that label use.\nEach crosses ``seed_count`` on its own.","properties":{"alpha":{"title":"Alpha","type":"number"},"confidence_floor":{"title":"Confidence Floor","type":"number"},"default_pool":{"$ref":"#/components/schemas/PoolStatus"},"embedding_model":{"title":"Embedding Model","type":"string"},"granularity":{"title":"Granularity","type":"string"},"k":{"title":"K","type":"integer"},"policies":{"items":{"$ref":"#/components/schemas/LearnedPolicy"},"title":"Policies","type":"array"},"seed_count":{"title":"Seed Count","type":"integer"},"tasks":{"items":{"$ref":"#/components/schemas/TaskPool"},"title":"Tasks","type":"array"},"user_id":{"title":"User Id","type":"string"},"workspace_id":{"format":"uuid","title":"Workspace Id","type":"string"}},"required":["user_id","workspace_id","embedding_model","seed_count","granularity","alpha","k","confidence_floor","default_pool","tasks","policies"],"title":"RouterStatus","type":"object"},"PoolStatus":{"properties":{"records":{"title":"Records","type":"integer"},"warm":{"title":"Warm","type":"boolean"}},"required":["records","warm"],"title":"PoolStatus","type":"object"},"LearnedPolicy":{"description":"A policy whose selection depends on routing memory, for the status overview.\n\nOnly a *learned* policy belongs here. A weighted policy names a router too, but\nits split is written in the policy document, so listing it under a warmth report\nwould tie it to a pool it never reads.","properties":{"backend":{"title":"Backend","type":"string"},"candidates":{"items":{"type":"string"},"title":"Candidates","type":"array"},"default_target":{"title":"Default Target","type":"string"},"name":{"title":"Name","type":"string"}},"required":["name","backend","candidates","default_target"],"title":"LearnedPolicy","type":"object"},"TaskPool":{"properties":{"records":{"title":"Records","type":"integer"},"task_id":{"title":"Task Id","type":"string"},"warm":{"title":"Warm","type":"boolean"}},"required":["task_id","records","warm"],"title":"TaskPool","type":"object"},"HTTPValidationError":{"properties":{"code":{"const":"invalid_request","description":"Stable error code, also sent as the Otari-Error-Code header.","title":"Code","type":"string"},"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail","type":"array"}},"title":"HTTPValidationError","type":"object"},"ValidationError":{"properties":{"ctx":{"title":"Context","type":"object"},"input":{"title":"Input"},"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location","type":"array"},"msg":{"title":"Message","type":"string"},"type":{"title":"Error Type","type":"string"}},"required":["loc","msg","type"],"title":"ValidationError","type":"object"}}},"paths":{"/api/v1/routing/status":{"get":{"description":"Report how warm one user's routing memory is in one workspace, per pool.\n\n``user_id`` is required rather than optional because there is no aggregate\nanswer: warmth is per user, and a total across users would describe a pool\nthat no request ever votes over. The same holds across workspaces, which is\nwhy ``workspace_id`` narrows rather than aggregating; it merely defaults\ninstead of being required, because a single-workspace deployment has one\nanswer.","operationId":"routing-routing_memory_status","parameters":[{"description":"Whose routing memory to report on.","in":"query","name":"user_id","required":true,"schema":{"description":"Whose routing memory to report on.","title":"User Id","type":"string"}},{"description":"Which workspace's routing memory to report on. Omit for the default workspace.","in":"query","name":"workspace_id","required":false,"schema":{"anyOf":[{"format":"uuid","type":"string"},{"type":"null"}],"description":"Which workspace's routing memory to report on. Omit for the default workspace.","title":"Workspace Id"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RouterStatus"}}},"description":"Successful Response"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}},"description":"Validation Error"}},"summary":"Routing Memory Status","tags":["routing"]}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.otari.ai/otari/for-integrators/api-reference/routing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
